Deployshed builds, deploys and runs an application from a git repository — no Dockerfile, no CI configuration and no Kubernetes manifest required from you. Push a repository, get a URL.
How it works
A push to an app's branch runs the same pipeline every time:
Pushto the app's branch
→
BuildDockerfile chosen, image built and pushed
→
Scansecrets, code, dependencies
→
Releaseyour release command, if any
→
Liveapplied to the cluster, rollout healthy
Push. The repository's webhook tells deployshed about the push, and a deployment is queued.
Build. deployshed checks out the branch, picks a Dockerfile (yours, a generated one, or one you accepted — see Dockerfiles), builds the image and pushes it to the registry, tagged with the build number.
Scan. The image and source are scanned. Under a blocking policy, a matching finding stops here.
Release. Your release command, such as a migration, runs once against the new image before it serves anything.
Live. deployshed applies the app's Kubernetes objects straight to the cluster it runs on — its own, or yours — and waits until the new pods are ready before marking the deployment succeeded.
There is no GitOps step in between: an app's configuration lives in deployshed itself, so pressing Deploy goes straight to the cluster rather than through a commit and a sync. A failure at any step keeps the previous version running, and the dashboard shows the real reason — a refusal, a compiler error, a rejected push — rather than the shell wrapper Docker prints it inside. See Deployments & builds.
What deployshed manages
Builds & runtimes
Nine languages detected automatically, with model-written Dockerfiles as a fallback. Runtimes →
Networking
A URL on day one; your own domain and TLS whenever you want it. Domains →
Data
PostgreSQL and Redis, provisioned and wired up in one click. Databases →
Scaling
Fixed replicas, autoscaling, or scale-to-zero when nobody's around. Scaling →
Security
Secret, code and dependency scanning on every build. Security →
Team & access
Roles, groups, SSO enforcement and required review. Team →
Architecture at a glance
Four services make up the platform itself. Control plane vs. data plane is the organizing idea: the gateway and a running app keep serving even when the build queue or the dashboard is down.
Control plane
api — the dashboard's backend, holds no cluster or git-write credentials
builder — drives detection, builds, scanning
deployer — the only service with cluster & git-write access
Data plane
gateway — routes every visitor's request
your app's pods
A fifth service, gitproxy, fronts the built-in git server for organizations that haven't connected their own.
Start here
Getting started
Three steps take a repository from source to a running, reachable app.
Before you begin: you need an organization (created automatically when you sign up) and a repository — public repositories need nothing further; a private one needs a git connection under Git integrations.
Create an appGive it a name and a repository URL. Leave branch, runtime and port on auto-detect unless you know you need to override them — deployshed reads the repository's own default branch and its manifests rather than asking you to restate them.
Watch the first buildThe app's Deployments tab streams the build log live. Detection picks a runtime, a Dockerfile is generated (or your own is used, if the repository has one), the image is built and pushed, and then the security scanners run against it.
It's liveOnce the rollout is healthy, the deployment is marked succeeded and the gateway starts routing to it at <app>.<org>.apps.deployshed.com.
A Dockerfile a model writes, only when detection or the template genuinely can't handle the repository, and only once a person has reviewed and accepted it — see Dockerfiles.
A repository whose own Dockerfile starts a development server (for example a bare npm start that runs a hot-reloading dev server) is refused rather than deployed — a dev server run in production is a common, hard-to-diagnose way for an app to look "up" while quietly failing every real request.
Reading a failed build
The app's Overview shows the actual reason a deploy failed, pulled out of the build log — a refusal message, the compiler's own error, or a registry's rejection — instead of Docker's shell wrapper around it. The full log is on the Deployments tab.
Guides
Environment variables & secrets
Set per app, on the Config tab. Changing one redeploys the app so it takes effect.
Plain vs. secret
A variable marked secret is encrypted at rest and never shown again in the dashboard after it's saved — only replaced. A plain one is visible to anyone who can view the app.
Set automatically
Adding a database or cache add-on writes its connection string for you:
Add-on
Variable
PostgreSQL
DATABASE_URL
Redis
REDIS_URL
Build-time variables for a frontend
A frontend build only ever inlines a variable that carries its bundler's own public prefix — REACT_APP_, VITE_, VUE_APP_, NEXT_PUBLIC_, NG_APP_. That convention isn't deployshed's invention: it's each bundler's own documented rule for what it's safe to ship in a bundle every visitor downloads. A variable without one of those prefixes never reaches client-side code.
Guides
Runtimes & detection
Detection reads manifests, never source code — a go.mod means Go the way counting .go files never could.
Language
Detected from
Notes
Go
go.mod
Finds the right cmd/ package on its own in a multi-binary repo
Node.js
package.json
A dev-server start script is refused, not run in production
Python
requirements.txt, pyproject.toml, Pipfile, setup.py, or a bare wsgi.py
A Django-shaped repo with no root script runs under gunicorn automatically
Java
pom.xml or build.gradle
Built with Maven or Gradle, run on a JRE-only final image
PHP
composer.json, or index.php alone
MySQL and PostgreSQL drivers are installed on every build
Ruby
Gemfile
Recognizes Rails, a plain Rack app, or a bare script, in that order
Rust
Cargo.toml
Refuses a build that binds 127.0.0.1 directly — unreachable from outside its own container
Static site
an index.html with no manifest
Served by nginx
Single-page app
a frontend build with no server
Built once at image build time, served as static files — never run as a live process
A repository's own Dockerfile always wins over every row above. See Dockerfiles.
Guides
Dockerfiles
Three ways an app gets built, tried in order, only ever falling further when the one before genuinely can't handle the repository.
Your own DockerfileCommitted in the repository. Always wins, unread and unmodified.
A generated templateOne fixed template per detected runtime — see Runtimes & detection. Deterministic: the same commit builds the same way every time.
A model writes oneOnly when detection finds nothing a template can handle. The operator's own model, served by Ollama on their own hardware, never a hosted API — it's given a description of the repository (file tree, manifests, README), never its source.
Nothing a model writes builds automatically. It appears on the app's Dockerfile tab for a person to read and accept first — and every accepted one is re-validated on every later build, so a rule added afterward still applies.
What the validator refuses
Before anything generated is offered for review, it has to pass a validator that rejects rather than repairs:
Every FROM must resolve to the deployment's base-image mirror, with an explicit version tag
No downloading a script and piping it into a shell or interpreter
No secrets, no credential-shaped ARG or ENV
The final stage can't be a build image, and can't install a compiler
EXPOSE has to match the declared port
No shell variable inside the array form of CMD, since no shell ever expands it there
Guides
Release commands
A command that runs once, against the newly built image with real deployed credentials, before the new version starts serving.
Suggested automatically from evidence in the repository, and editable on the app's Overview before it ever runs:
Evidence
Suggested command
manage.py (Django)
python manage.py migrate — plus collectstatic when whitenoise is a dependency
Rakefile (Rails)
bundle exec rails db:migrate
knex, prisma, typeorm, sequelize-cli, drizzle-kit in package.json
that tool's own migrate command
alembic.ini
alembic upgrade head
A command that fails stops the deploy — the previous version keeps running rather than serving a version whose migration never applied.
Guides
Worker apps
A second app kind for a queue consumer or a background job — anything that isn't meant to receive requests.
Set an app's kind to worker and deployshed stops creating a port, a health check, a Service, or an Ingress for it. It's a Deployment that runs, nothing more — no URL, because there's nothing for a URL to reach.
Switching an existing web app to worker (or back) asks for confirmation — it changes how the app is reached, not just how it's labeled.
Guides
Monorepos
One repository, several apps — each pointed at its own directory.
An app's source directory setting scopes both detection and the build context to that path. Create one deployshed app per service in the repository (an API, a worker, a frontend), each with its own directory, its own runtime, and its own environment variables — they can still share the one repository and branch.
Guides
Deploy on push
A push to an app's branch builds and deploys automatically, with no manual step.
A webhook is configured on the repository the first time an app is created against it, scoped to the app's own branch. Pushing anywhere else does nothing on its own — unless your organization requires review, in which case it opens a change instead.
Reference
Deployments & builds
Every build and every rollout is one deployment record, on the app's Deployments tab.
Status
Meaning
queued
Waiting for a build worker
building
Image is being built and scanned; the log streams live
deploying
Image is built; the cluster is applying the new manifest
succeeded
The rollout is healthy and serving
failed
Stopped at some step; the previous version is still running
cancelled
Superseded by a newer deploy before it finished
Rollback
Rolling back redeploys a previous succeeded deployment's already-built image — no rebuild, so it's as fast as the cluster can roll a new revision out.
Reference
Runs
A one-off command against the app's own image, in its own namespace, with its own environment — for a migration you want to trigger by hand, or a quick look inside the running image.
# from the app's Run tab
$ ls -la
$ php artisan tinker
$ python manage.py shell
A run is time-bounded and never affects the running app's own pods — it starts a separate, short-lived one.
Infrastructure
Connections
How deployshed reaches the systems around it: where your code lives, what builds it, where images go, where apps run, and where their databases and buckets are provisioned.
Connections live under Settings → Connections. Owners and admins can manage them; other roles don't see the tab.
You may not need any
Every deployment starts with defaults its operator configured, one per kind — that's what lets a new organization deploy a public repository without setting anything up. They appear in your list so you can see and test what your apps are actually using, but only the operator can change them.
Adding a connection of your own overrides the default for that kind, for your organization only. For each kind, deployshed uses:
your organization's default connection of that kind, if it has one;
otherwise, the deployment's default.
Delete yours and apps fall back to the deployment default again.
A Postgres server apps get a database of their own on
PostgreSQL
Cache
A Redis server apps get a scoped user on
Redis
Object storage
A bucket and credential per app
Google Cloud Storage
Metrics
Per-app CPU, memory and request rates
Prometheus (or anything that speaks its query API)
Secrets
Where app configuration is stored
Kubernetes Secrets Vault, AWS planned
Planned providers are listed in the dashboard but can't be chosen yet.
Adding one
Pick a kind and a providerThe form shows only that provider's fields, with a note on each saying what it's for.
Fill it inAnything secret — tokens, passwords, keys — is encrypted when saved and never shown again. To change one, you replace it.
Save and testSaving tests the connection straight away, so a wrong URL or a token missing a scope shows up now rather than in your first failed build. You can re-test any connection later, including the deployment's defaults.
What each token needs
Provider
Permissions
GitHub
Repo access (to read code and manage the push webhook). Add repository creation only if deployshed should create repositories for you.
GitLab
A personal or group access token with api scope.
Bitbucket
An Atlassian API token with repository read, write and admin, plus webhook and pull request scopes. Without admin everything else works, but pushes never trigger a build.
Gitea
Create repositories and manage webhooks.
Jenkins
Job create, build and read. Add credentials create and update so deployshed can manage clone credentials per git server.
Harbor
A robot account on the project.
Amazon ECR
ecr:GetAuthorizationToken, ecr:CreateRepository, and push/pull. deployshed exchanges the key for a 12-hour token and refreshes it; the key itself never reaches a build.
Kubernetes
A service account token bound to a role. Testing reports exactly which permissions are missing.
PostgreSQL
An admin user with CREATEDB and CREATEROLE. Used only to create per-app databases and roles, never to read app data.
Redis
A password allowed to run ACL SETUSER.
Google Cloud Storage
Create buckets, service accounts and HMAC keys. Leave the key empty when the platform runs with its own Google identity (GKE Workload Identity).
More than one git server
An organization can connect several source control servers — say, GitHub for most things and a self-hosted Gitea for one team. One is the default. When you create an app, you choose which server its repository is on; for an existing repository, deployshed can also tell from its address.
An app's git server is set when it's created and can't be changed afterwards — a repository on a different server is a different repository. Create a new app instead.
Things that trip people up
"Reachable from the cluster." Database, cache, git and registry addresses are used from inside the cluster your apps run on, not from your browser. For an app on your own cluster, that means reachable from that cluster.
Registry hosts must resolve on the nodes. Images are pulled by the node itself, not by a pod, so a registry address that only resolves inside the cluster's own DNS fails every pull.
Deleting a connection sends apps that relied on it back to the deployment default, if there is one — check what they'll be using first.
Infrastructure
Custom domains
Every app gets <app>.<org>.apps.deployshed.com the moment it deploys. Pointing your own domain at it is optional.
Add the hostnameOn the app's Domains tab. It appears as pending.
Point DNS at the target shownThe Domains tab shows the address of the cluster this app runs on. If it's a hostname, create a CNAME to it; if it's an IP address, create an A record — a CNAME can only point at another hostname.
Certificate issues automaticallycert-manager handles the certificate end to end once DNS resolves — nothing to configure. The domain flips to active on its own.
Which address to point at
Always the one the Domains tab gives you for that app, never an address copied from another app. An app on your own cluster is served by that cluster's gateway, at that cluster's own address — pointing its domain at deployshed's shared address reaches a cluster with no route for it, and the domain can show active while a browser still can't open it.
Cloudflare and other proxying DNS providers
Set the record to DNS only (the grey cloud in Cloudflare), not proxied. The certificate deployshed issues lives on the cluster; a proxy in front terminates TLS with its own certificate instead, and only works at all if its SSL mode is set to Full (strict).
Stuck on pending? Check the record with dig +short your.domain — it should return the target the Domains tab shows. Issuance usually takes a minute or two once it does.
Custom domains are only offered for apps set to public access. A signed-in session's cookie is scoped to deployshed's own domain tree — it can never be valid on a domain you own, so a private app on a custom domain would be an unbreakable login loop.
Infrastructure
Databases & storage
A PostgreSQL database, a Redis user or a storage bucket for an app, provisioned in one click from its Databases tab.
Adding one creates it, writes the credentials onto the app as environment variables, and redeploys so the running pod has them. Removing an add-on removes the variables — never the underlying data. Adding a PostgreSQL or Redis add-on back reconnects the app to the same database or user.
Add-on
What the app gets
Variables set
PostgreSQL
A database and a role of its own
DATABASE_URL
Redis
A user limited to its own key prefix
REDIS_URL
Object storage
A bucket and a credential scoped to it
S3_BUCKET, S3_ENDPOINT, S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, and the matching AWS_* names
Object storage is S3-compatible: an app written for Amazon S3 works unchanged, because the endpoint is set as AWS_ENDPOINT_URL_S3, which the AWS SDKs already read.
Where they're provisioned
deployshed never runs a database itself. It provisions into a server behind a connection: your organization's own, if you've added one, or otherwise the one the deployment's operator configured. The admin credential on that connection is used only to create per-app databases, users and buckets — never to read app data.
Apps on your own cluster. The database has to be reachable from the cluster the app runs on. The deployment's default server usually sits on deployshed's own network, which an app on a BYOC cluster can't reach. Add a database connection to a server your cluster can reach, and new add-ons are provisioned there.
PHP builds include mysqli, pdo_mysql, pgsql and pdo_pgsql, so a PHP app can talk to either engine. MySQL isn't an add-on; point the app at a MySQL server yourself with an environment variable.
Infrastructure
Resources & scaling
CPU, memory and replica settings live on an app's Kubernetes tab — typed, bounded fields, never a raw manifest patch.
Resources
CPU and memory requests and limits, checked against the namespace's quota for every replica running at once — not just one, since that's the arrangement that actually has to fit.
Replicas & autoscaling
Equal min and max replicas hold a fixed count. A higher max creates a real HorizontalPodAutoscaler on CPU load, with its own target percent and scale-down delay.
Autoscaling and idle sleep are mutually exclusive: a CPU-based autoscaler can't scale below one replica, so an autoscaled app is never a candidate for scaling to zero.
Idle sleep
An owner can opt an organization into scaling its apps to zero once every session in it has ended and stayed that way past a grace period — and back up the moment anyone signs in again. Public apps are exempt: they have visitors of their own, unrelated to anyone's session.
BYOC placement
Node selectors, tolerations, and custom labels/annotations are only offered for an app running on your own cluster — on deployshed's own cluster, nodes and labels are the platform's to decide.
Infrastructure
Bring your own cluster
Connect a Kubernetes cluster your organization controls, and deploy apps to it through the same pipeline.
Once connected, an app can be assigned to that cluster instead of deployshed's own. Deploys still go through detection, the build and scanning exactly the same way — only where the manifest is finallyapplied changes.
Running on your own cluster is also what unlocks node placement, tolerations and custom labels per app — settings that only make sense once the cluster isn't shared infrastructure.
A database add-on is provisioned on whichever server your database connection points at — by default the deployment's, which a BYOC cluster usually can't reach. Add a database connection to a server your cluster can reach before relying on add-ons there.
Infrastructure
Git integrations
Keep your code where it already is, or let deployshed host it.
Public repositories need nothing at all — they're read anonymously, from any host.
The deployment's git server — every organization can use it with no setup. deployshed creates the repository for you; push to the address the app shows.
GitHub, GitLab, Bitbucket or your own Gitea — add a source control connection. Private repositories need one, and it's also how deployshed creates new repositories on that server for you.
You can connect more than one server; each app picks its server when it's created. See Connections for what each provider's token needs.
A push webhook is added to the repository automatically the first time an app is created against it — see Deploy on push.
Platform
Security scanning
Three scanners run against every build, in parallel, inside the build pod.
Tool
Checks
Reports
gitleaks
Committed secrets
Rule, file and line only — never the secret's value
Semgrep
Risky code patterns
Severity taken from the rule's own declared impact
Results land on the app's Security tab, with the SBOM available to download. An organization's policy decides what happens next:
Policy
Effect
Off
Nothing runs
Advisory default
Everything reported, nothing blocks a deploy
Block on critical / Block on high
A matching finding stops the deployment before production
A blocking policy also blocks a deploy whose scanners didn't finish — an outage never gets read as a clean scan.
Platform
Team & access
Four roles, groups for managing members in batches, and optional single sign-on.
Role
Can roughly
Owner
Everything, including billing-level and security-policy settings
Admin
Manage apps, members and settings, short of the owner-only ones
Developer
Create and deploy apps
Viewer
Read-only
Single sign-on
An organization can require SSO outright for its verified domains, gate access further by identity-provider group, and sync a member's role from that provider's groups automatically.
Required review
When turned on, a push to a branch other than an app's own opens a change for review instead of deploying immediately. Merging needs approval from somebody other than whoever merges, and an approval covers the exact commit it was given for — a later push asks for a fresh one. An organization with nobody else able to deploy is exempt automatically.
Audit log
Every meaningful action — who deployed what, who changed a setting, who approved a merge — is recorded and visible to admins and owners.
Help
FAQ
Can I use my own Dockerfile?
Yes — a Dockerfile committed in the repository always wins over anything deployshed would generate, unread and unmodified.
My app deployed but I can't reach it. Why?
Almost always a port or bind-address mismatch: the app has to listen on 0.0.0.0 (not 127.0.0.1) on the port deployshed set. Detection catches the common shapes of this automatically — a Rust build that binds the loopback address directly is refused outright rather than shipped unreachable.
Why did onboarding say my repository "can't be read without a credential"?
Usually a branch mismatch, not a permissions problem — a public repository whose default branch isn't main used to be assumed wrong instead. Branch detection now reads the repository's own default.
What happens if a model-written Dockerfile is wrong?
It's never built without review. Every one goes through a validator first, then a person has to accept it on the app's Dockerfile tab — nothing generated runs automatically.
Does deployshed support MySQL?
Not as an add-on — those are PostgreSQL, Redis and object storage today. A PHP app can still talk to a MySQL server you run yourself; the drivers ship by default.
Why can't my BYOC app reach the database I provisioned?
It was provisioned on the deployment's default database server, which sits on a network your cluster has no path into. Add a database connection to a Postgres server your cluster can reach, and add-ons are provisioned there instead. See Databases & storage.