Deploy from source
Build and deploy your app straight from its source directory — Guidal builds the image, so no local Docker is needed.
Point Guidal at the directory your application lives in and it does the rest: the CLI packs the directory and uploads it, Guidal builds a container image, and the new image rolls out to your service. You do not need Docker installed, you never handle a registry credential, and for a service that already exists you never handle an image reference either.
How it works
guidal deploypacks the directory and uploads it.- Guidal builds the image. A regular file named exactly
Dockerfileat the root of the directory is used when there is one; without one, Guidal detects the language — Node, Python, Go, Ruby, Java, PHP, Rust and static sites — and builds anyway. - When the build succeeds, the image rolls out to your service.
A typical build takes one to three minutes.
Only the root Dockerfile is looked for. A lowercase dockerfile, a Containerfile or a Dockerfile in a subdirectory is not picked up; point at it with --dockerfile <path>, which also tells Guidal to build with that file. A root Dockerfile that is a symlink or a directory fails the build: replace it with a real file.
guidal builds get shows builder, what you asked for, and resolved_builder, what ran: dockerfile, or detected when Guidal detected your stack. resolved_builder is empty until the build reaches its build step.
Before you deploy
Know your port. Guidal does not set a PORT variable for you — your application decides where it listens, through its start command or its framework's default. Pass that same number when you create the service. A mismatch is the most common reason a new service never starts serving.
Know what is uploaded. Everything in the directory is uploaded except .git and node_modules/.cache. To leave more out, add a .guidalignore file, which uses .gitignore syntax. When there is no .guidalignore, a .dockerignore is used instead. A .gitignore is not read.
Editor and agent folders are left out by default too: .cursor/, .vscode/, .idea/, .claude/, .windsurf/ and .DS_Store, at any depth. To upload one anyway, re-include it with a ! line in .guidalignore — !.vscode/, say.
Secret files are refused. A deploy that would upload a file that looks like a secret — .env, .env.*, *.pem, *.key, *.p12, *.pfx or an SSH private key — stops before anything is uploaded and names the files. Templates such as .env.example, .env.sample and .env.template are allowed. Exclude the files in .guidalignore, and set the values with guidal env set or guidal secrets set instead. If a matching file is deliberately public — a committed .env.test, say — re-include it with a !<path> line.
A Python virtualenv carries files that match these patterns, and should never be uploaded anyway; exclude it too.
A typical .guidalignore:
.env*
!.env.example
node_modules/
.venv/If your app is a static site that serves a built dist/ directory, make sure dist/ is not excluded — it has to be uploaded.
Deploy
To an existing service — build, roll out, and wait:
guidal deploy . --service webFor a new service, build first, then create the service from the image reference the build reports:
guidal deploy .
guidal services create --name web --image <image reference> --port 3000--service must name a service that already exists. Without it, the image is built and stored but nothing is deployed. Later deploys use guidal deploy . --service web.
Two flags worth knowing:
--no-waitsubmits the build and returns its id immediately.--followprints the build log while it waits.
Follow and diagnose a build
guidal builds list
guidal builds get <build-id>
guidal builds logs <build-id>
guidal builds cancel <build-id>The build log opens in a short view: each build step and its result, your own commands' output, and every error and warning. Platform housekeeping lines — layer download progress, image export and push — are left out. To see every line exactly as the build printed it, turn on Show raw log under the log in the console, or run guidal builds logs <build-id> --raw. Redirected to a file, guidal builds logs writes the full log.
When a build fails, guidal builds get shows the reason, and guidal builds logs shows the command that failed:
| Reason | What it means | What to do |
|---|---|---|
build_failed | A build step exited with an error — a compile error, a failed install, a missing file | Find the failing command in the log, fix the source, deploy again |
prepare_failed | The root Dockerfile is a symlink or a directory; or there is no root Dockerfile and no build plan could be made: the language was not recognised, or planning failed | Read the log; replace a symlinked or directory Dockerfile with a regular file, or add a Dockerfile |
source_too_large | The uploaded directory is over your plan's limit | Exclude build output, dependencies, data and media in .guidalignore |
timeout | The build ran past your plan's time limit | Look for a step waiting on the network; shrink the upload |
quota_exceeded | Guidal's build capacity was full when the build was scheduled | Deploy again a little later |
source_missing | The stored source has expired — uploads are kept for 30 days | Deploy again from your machine with guidal deploy |
digest_mismatch | The upload did not arrive intact | Deploy again |
attestation_failed | The image built, but Guidal could not sign it. Your source is not at fault | Change nothing; deploy again once the issue is resolved, and contact support if it repeats |
internal | A platform-side failure | Deploy once more; if it repeats, contact support |
A deploy refused with build limit reached means another build for your organization is still running. Wait for it to finish, then deploy again.
From an AI agent
Your editor's assistant does the same through MCP with deploy_from_source: it packs and uploads the project directory and follows the build, under the same rules for ignored and secret files. See Deploy with an AI agent.
Already have an image?
If you build images yourself, push them to the registry Guidal provides and create a web service from the image. Build them for linux/amd64.