Skip to content

Build System

deploybase builds static sites in isolated Kubernetes Jobs. Each build gets its own container with controlled resources and network access.

1. Git clone (branch + commit)
2. Install dependencies (framework-specific)
3. Run build command
4. Upload output directory to Bunny.net CDN storage
5. Configure CDN edge rule (production or preview)
6. Update deployment status
7. Send notification email

Each build runs in a dedicated Kubernetes Job pod:

Resource Limit
CPU 1 core
Memory 2 GB
Disk 10 GB temporary storage
Timeout 10 minutes
Network Isolated namespace

Builds cannot access other builds, the deploybase database, or internal services. They can access the public internet (for downloading dependencies from npm, crates.io, etc.).

Each framework uses a specific Docker image:

Framework Image
Next.js, SvelteKit, Astro, Vite, Gatsby, Custom node:24-alpine
Hugo hugomods/hugo:0.139.0
Jekyll jekyll/jekyll:4

The install and build commands run inside this image.

Node frameworks can install dependencies with npm, pnpm, yarn or bun. The manager is resolved in this order:

  1. The project’s package_manager field, if you set one (npm, pnpm, yarn, bun).
  2. The packageManager field in your package.json (the Corepack convention, for example "packageManager": "pnpm@9.15.0").
  3. The lockfiles committed to the repository.
  4. npm, if nothing else matches.

Recognized lockfiles:

Package manager Lockfiles
npm package-lock.json, npm-shrinkwrap.json
pnpm pnpm-lock.yaml
yarn yarn.lock
bun bun.lock, bun.lockb

If several lockfiles are present and package.json does not say which manager to use, precedence is pnpm, then yarn, then bun, then npm.

When a matching lockfile is committed, the install uses the reproducible variant (npm ci, or --frozen-lockfile / --immutable), so the build fails rather than silently resolving different versions. Without a lockfile, a plain install runs.

Lifecycle scripts are disabled during install for every package manager (--ignore-scripts). Dependencies cannot run arbitrary code at install time in a deploybase build. For bun this also overrides trustedDependencies and any bunfig.toml in the repository, because the flag wins over config files. Your own build script still runs normally.

The build command is not rewritten per manager: npm run build runs the build script from your package.json whichever manager installed the dependencies.

The full build command is constructed as:

{install_command} && {build_command}

For Hugo (no install step), only the build command runs: hugo --minify.

Custom build commands can be set per project. They are validated for safety — shell metacharacters (&, ;, |, `, $, ()) are rejected to prevent command injection. See Supported Frameworks for validation rules.

After a successful build, the contents of the output directory are uploaded to Bunny.net CDN storage at:

/{tenant_id}/{project_slug}/{deployment_id}/

Uploads run concurrently (10 parallel workers) with automatic Content-Type detection based on file extension.

Build minute usage is tracked per billing period. Limits depend on the subscription plan — see pricing for current limits.

When a build exceeds the 10-minute timeout, it is terminated and the deployment status is set to failed.

Pending, queued, or building deployments can be cancelled:

Terminal window
curl -X POST https://api.deploybase.eu/api/v1/deployments/DEPLOYMENT_ID/cancel \
-H "Authorization: Bearer $TOKEN"

Cancelled builds do not count toward build minute usage.