Everything you need to run apps on Dbrij Hosting: ways to deploy, builds and monorepos, services, variables, URLs, custom domains, logs and rollbacks, databases and imports, plans, the CLI and AI assistants.
Dbrij Hosting runs your web apps, APIs, background workers and managed databases. You bring code from a Dbrij Source repository, a GitHub repository, a folder on your machine, a container image or a single file function. Hosting builds it, runs it, gives it HTTPS, and keeps its logs, deployments and backups where you can reach them.
Everything lives in a project, and a project holds services. A project belongs to a space: your personal space, or a company you are a member of. The space decides who can see the project, who can deploy it and who is billed for it. Services in one project reach each other privately, which is how an app talks to its database.
There are three ways in, and they all act on the same projects:
dbrij command line tool, which ships the folder you are standing in (see CLI reference).Prefer a guided walkthrough? The Hosting guide takes you from nothing to a live app step by step.
From a folder on your machine to a live HTTPS address in three commands. You need Node.js for npx.
1. Sign in. The terminal shows a short code and opens your browser. Confirm the code matches in a browser where you are signed in to Dbrij. No password ever goes through the terminal.
npx dbrij login2. Link the folder to a service. Pick a project and a service, or create new ones. A new project asks which space it belongs to. The link is saved in .dbrij/project.json, which stays out of git.
npx dbrij link3. Deploy. The folder is packed, uploaded and built. Before the build starts you are asked whether the service should get a public URL.
npx dbrij deploy
# Deploying shop / web
# · Packed 214 files (1.8 MB compressed)
# · Uploaded
# Deployed.
# https://<service>.dbrij.appCode on GitHub or Dbrij Source? Open Hosting, create a project, and choose the repository in the Deploy dialog. Pushes to the branch you pick then deploy on their own.
Every service has one source. It is set when the service is created and can be changed later in its settings.
A service that builds from a Dbrij Source repository deploys when you push to the branch it tracks. Nothing has to be registered on the repository: the push itself starts the build. Pushes to other branches are ignored by that service. To push with your Dbrij sign in instead of a token, run dbrij git setup once.
npx dbrij git setup # once per machine
git push # deploys the service that tracks this branchConnect GitHub once from Hosting, then pick a repository and a branch. Dbrij puts the deploy webhook on the repository through your connected account, so you never paste a URL into GitHub. The service page shows whether pushes reach Dbrij, and a single button sets the webhook up again if it was removed or GitHub stopped trusting it.
A repository service deploys on every push by default. Switch automatic deploys off to set a service up first and ship it by hand: the Deploy button keeps working, only the push nobody is watching is held. A service can also hold automatic deploys while its last code scan found malware.
dbrij deploy packs the linked folder and ships exactly what is on disk: no git remote, no webhook. Files matched by .gitignore and .dbrijignore stay behind, and so do installed dependencies, build output, caches and secrets (.env files, *.pem, *.key, id_rsa) whatever your ignore files say. The packed folder must be under 100 MiB compressed. Only services created for uploads can take a dbrij deploy.
Give the service an image reference and Hosting runs that image as it is, with no build step.
A function is a single source file that runs on Bun, edited in the service's Code tab. Saving it is the deploy. A new function starts from a small server that answers on the port in PORT. The file can be up to 100,000 characters.
const server = Bun.serve({
port: Number(process.env.PORT ?? 8080),
fetch(req: Request) {
const url = new URL(req.url);
if (url.pathname === "/") return new Response("Hello from your Dbrij function!");
return new Response("Not found", { status: 404 });
},
});A template deploys into a project in one click: it creates and deploys every service it describes. A service can also be created empty, with no source yet, to configure first; deploying it is refused until a source is added.
A service can have a staging mirror: a copy that builds and runs beside it with its own address. When the mirror is right, promote it and production receives the exact image you tested, without a rebuild.
Pick a repository and the Deploy dialog scans it, the same way the CLI's scan_folder tool scans a folder. The scan reads only small files (package manifests, compose files, Dockerfiles), never the whole tree, and offers each deployable directory as a choice. A directory counts as an app when it holds one of: package.json, go.mod, requirements.txt, pyproject.toml, Pipfile, Cargo.toml, pom.xml, build.gradle, build.gradle.kts, Gemfile, composer.json, mix.exs, deno.json, or a .NET project or solution file (.csproj, .fsproj, .vbproj, .sln). It looks up to three folders deep and skips folders such as node_modules, dist, test, docs, examples and scripts.
For each app it suggests a name, the framework, a port and a role, and says when an app cannot run on Hosting at all (a mobile app, for example).
FRAMEWORK SUGGESTIONS
| Next.js, Nuxt, Remix | site · port 3000 | Pages people visit. |
| Astro | site · port 4321 | Pages people visit. |
| Vite | site · port 8080 | Pages people visit. |
| NestJS, Fastify, Express, Hono | api · port 3000 | Endpoints for apps. |
| Dockerfile with EXPOSE | port from EXPOSE | The first EXPOSE line sets the suggested port. |
| React Native, Expo | not hostable | A mobile app is shown with the reason it cannot run here. |
A repository whose root organises rather than runs (a pnpm-workspace.yaml, or a root package.json with a workspaces field) is treated as a workspace. Each app inside it is offered on its own. Set the service's Root directory to the app's folder, for example apps/web.
When that app uses sibling workspace packages (pnpm, npm or Yarn workspaces, Turborepo or Nx), Dbrij Pack installs the whole workspace from the repository root, then builds and starts only that app. No Dockerfile is needed. Folders that are not part of a JavaScript workspace build on their own. See How builds work.
While the new builder rolls out, the Deploy dialog may still mark such an app as needing a Dockerfile, and a service not yet on the new builder still needs one. A Dockerfile that copies the whole repository works on every builder. Directories that carry their own Dockerfile are always safe to pick. A service can point at a named Dockerfile, such as Dockerfile.web, with its Dockerfile path.
The scan also suggests managed databases, from compose service images or from dependencies:
| postgres | PostgreSQL | A postgres image in compose, or pg, postgres, @prisma/client, typeorm or drizzle-orm in dependencies. |
| mysql | MySQL | A mysql or mariadb image, or mysql or mysql2 in dependencies. |
| mongodb | MongoDB | A mongo image, or mongoose or mongodb in dependencies. |
| redis | Redis | A redis or valkey image, or ioredis, redis, bullmq or bull in dependencies. |
In order of preference:
dist). A site with a package.json is built first; plain HTML is served as it is. Hosting then serves that folder itself, with single page app fallback. No Dockerfile needed. Choosing Static site is an explicit choice, so a leftover Dockerfile in the folder does not take over.Dockerfile in the root directory, built as written.dbrij.json file. See How builds work.BUILD SETTINGS
| rootDir | string | The folder inside the repository the app lives in. Empty means the root. |
| dockerfilePath | string | A specific Dockerfile, relative to the repository. |
| staticOutputDir | string | Static site mode: the folder the build leaves its files in. Empty turns it off. |
| installCommand | string | Overrides the detected install command, for example npm install. |
| buildCommand | string | Overrides the detected build command. |
| startCommand | string | Overrides the detected start command. |
| releaseCommand | string | Runs once against the new image, after the build and before any traffic moves. Database migrations go here. |
When a dbrij.json file in the app folder sets the install, build or start command, the file wins over the same setting here, because the file is reviewed in pull requests like the rest of the code.
A release command runs once per deploy, never once per copy, so two copies can never migrate one database at the same time. If it exits with an error the deployment fails and the previous version keeps serving. Before it runs, every PostgreSQL, MySQL and MongoDB database in the project is backed up, and the command waits for those backups to land. The newest three of these pre release backups are kept per database.
| queued | in flight | Waiting to build. On the free plan a deploy can wait here for a build slot; paid plans skip the wait. |
| building | in flight | The image is being built. |
| releasing | in flight | The release command is running. Only for services that set one. |
| deploying | in flight | The new version is rolling out. |
| active | finished | Live. |
| failed | finished | The build, release or rollout failed. The previous version keeps serving. |
| cancelled | finished | Stopped before it finished. |
| superseded | finished | A newer deployment replaced it before it went live. |
When a build fails, Hosting reads the log and writes what went wrong in plain words, the log lines it matched and what usually fixes it. It also says whose side the problem is on: on our side, where pressing Deploy again is the fix, or a fix in your repository. When the fix is a setting Hosting can change (a different install command, for example), the deployment offers to apply it and deploy again.
Your first deploy may ask you to verify a payment method with a small one time charge. A paid Hosting plan already counts as verified.
When a service has no Dockerfile, Dbrij builds it with Dbrij Pack, the builder behind Hosting. Dbrij Pack looks at the files in the app folder, works out the language, the framework and the package manager, and writes a build recipe for it. The build log says what it found in one short line.
A Dockerfile always wins. When the folder has one, or the service points at one, it is built exactly as written and Dbrij Pack is not used. The one exception is Static site: choosing it in Settings is an explicit choice, so a leftover Dockerfile does not take over.
Dbrij moves builds over to the new builder gradually, so what this page describes reaches every build as it rolls out. Until then a service builds the way Builds and detection describes.
DETECTED AND TUNED
| Node | npm, pnpm, Yarn, Bun | Next.js, Vite, Nuxt, Astro, Remix, NestJS, Express, Fastify and Hono. |
| Static sites | HTML, or a site with a build | Built when there is a package.json, then served as files. |
| PHP | PHP | Laravel and plain PHP apps. |
| Python | pip, uv, Poetry, Pipenv | Django, FastAPI and Flask. |
| Go | Go modules | Apps with a go.mod file. |
| Ruby | Bundler | Rails (assets built, run in production mode), Sinatra and Rack apps. Commit Gemfile.lock. |
| Java | Maven, Gradle | Spring Boot first. In a build with several modules the Spring Boot module is the app. |
| Rust | Cargo | Web apps such as Axum, Actix and Rocket. Cargo workspaces build one package from the root. |
| Elixir | Mix | Phoenix and other Mix apps, built as a release. Commit mix.lock. |
| .NET | C#, F#, Visual Basic | ASP.NET Core and console apps, alone or in a solution. |
| Deno and Bun | runtimes | A deno.json app, and Node projects that run on Bun. |
Gleam, C and C++ projects and start.sh scripts also build. A few kinds of project Dbrij recognises but does not build on its own (Scala with sbt, Clojure, Haskell, Swift, Dart and Flutter, Zig, Crystal, OCaml, Nim, Erlang with rebar3, Perl, R and Julia): the build stops at once and says to add a Dockerfile, which Dbrij then builds as written. If a stack needs something unusual, set the commands in dbrij.json or add a Dockerfile.
Set Root directory to the app's folder. When that folder belongs to a larger build (a Cargo workspace, a Maven or Gradle build with several modules, or a .NET project that uses projects beside it), Dbrij Pack builds from the root of that build and starts only your app. When a project holds several apps and nothing says which one to start, the build stops and names them; choose one with a variable in Settings:
VARIABLES THAT CHOOSE THE APP
| DBRIJ_PACK_JAVA_MODULE | Java | The folder of the app module, for example api. |
| DBRIJ_PACK_RUST_BIN | Rust | The binary to start, unless Cargo.toml already names its default binary. |
| DBRIJ_PACK_CARGO_WORKSPACE | Rust | The package of a Cargo workspace to build. |
| DBRIJ_PACK_DOTNET_PROJECT | .NET | The project to deploy, for example src/Shop.Web/Shop.Web.csproj. |
Runtimes and packages come from Dbrij's own mirror and local package caches, so an outage somewhere else does not stop a deploy: Node, Python, Go, PHP, Ruby, Java, Rust, Erlang and Elixir, .NET and Deno themselves, and packages from npm, PyPI, Go modules, Maven Central and the Gradle plugin portal, crates.io, RubyGems, Hex and NuGet. Your project's own registry settings, such as a private registry in .npmrc, a private gem source in the Gemfile or a NuGet.Config, still win.
Each service keeps its own build cache. A repeat build reuses every step whose inputs did not change, so the second deploy is faster than the first.
A service's variables reach the build as well as the running app, so values such as VITE_ and NEXT_PUBLIC_ ones are baked in at build time. Change one and deploy again to rebuild with it.
Build logs never show variable names: the log says only how many variables reached the build. Any variable value six characters or longer that the build prints is replaced with [hidden]. A few plain setting words stay visible because they fill every log: production, development, staging, preview, localhost, enabled and disabled.
To keep build settings with the code, add a file named dbrij.json at the root of the app folder (the service's Root directory). It must sit at the root, not inside the .dbrij folder: once a folder is linked, its .dbrij folder is ignored by git, so a file there would never reach the repository. The file is read when Dbrij Pack builds the service, so it does nothing next to a Dockerfile.
{
"$schema": "https://dbrij.com/schemas/dbrij.json",
"runtime": { "node": "22" },
"buildCommand": "npm run build",
"startCommand": "node dist/server.js"
}The $schema line is optional. Editors read it to autocomplete the keys and check their values.
KEYS
| installCommand | string | The command that installs your packages. |
| buildCommand | string | The command that builds your app. |
| startCommand | string | The command that starts your app. |
| runtime | object | Versions by name, for example { "node": "22", "python": "3.12" }. |
| staticOutput | string | Build the site, then serve this folder as a static site. |
| $schema | string | https://dbrij.com/schemas/dbrij.json, for editors. |
ADVANCED KEYS
| packages | object | Package name to version, for tools the build needs. |
| buildAptPackages | string[] | System packages installed for the build only. |
| deploy | object | The running image: startCommand, aptPackages (system packages it needs) and variables. |
| steps | object | Build steps by name, for full control over the recipe. |
| caches | object | Named caches that build commands can reuse between builds. |
| secrets | string[] | Names of build variables that build steps may read. |
A key written in full wins over its short form: deploy.startCommand over startCommand, for example. A command written in dbrij.json wins over the same setting in the service's Settings, because the file is reviewed in pull requests like code. If the folder holds both a dbrij.json and an older build settings file, dbrij.json is used and the log says a second file was ignored.
Set the Root directory to the app's folder, for example apps/web. For a JavaScript workspace (pnpm, npm or Yarn workspaces, Turborepo or Nx) where that app uses sibling workspace packages, Dbrij installs the whole workspace from the repository root, then builds and starts only that app. No Dockerfile is needed. Other folders build on their own.
Choose Static site in Settings with an output folder, or set staticOutput in dbrij.json. A site with a package.json is built, then the folder is served with single page app fallback, so a link to any route opens the app. Plain HTML is served as it is.
The diagnosis says whose side the problem is on. On our side means something in Dbrij failed, not your code: press Deploy again. Anything else names the fix to make in your repository.
Dbrij Pack is MIT licensed. It includes third party code under that code's own licences, and those notices ship with the builder.
| web | kind | Serves HTTP on its port, behind HTTPS. Can have a public URL and custom domains. |
| worker | web, background | Builds and runs like a web service but listens on nothing: no port, no URL, no domains. Queue consumers, schedulers, bots. |
| database | kind | A managed database engine with its own disk, reachable privately from the project. |
A web service can say what it is: a site (pages people visit, with the page and search tools shown) or an api (endpoints for apps, with those tools hidden). Left unset, Hosting decides from what the service's root actually returns. What you declare always wins.
Turn a web service into a worker from its settings, or create one as a worker. A worker has no health probe on a port, because it opens none; a worker that keeps crashing still shows in its restart count. Turning worker mode on requires removing the custom domains first, and drops the public URL.
| postgres | PostgreSQL | Relational SQL database for your app data. |
| mysql | MySQL | The other relational standard, widely supported. |
| mongodb | MongoDB | Document database for flexible, JSON like data. |
| redis | Redis | In memory store for caching, queues, and sessions. |
Databases are available on paid plans. See Databases for connections, backups and restores.
A web service can mount a persistent disk at an absolute path. A service with a volume runs a single copy, because a disk can only be attached in one place. Disks can grow but never shrink. Detaching a volume keeps the disk, so attaching it again finds the data.
Each service has its own environment variables. They are encrypted at rest, and only people who can operate the service see their values. In the browser the values appear only after you confirm who you are.
RULES
| Names | pattern | A letter or underscore, then letters, digits or underscores. |
| Values | size | A string under 8 KB. |
| Count | limit | Up to 200 variables per service. |
| Total | limit | All variables together up to 400 KB. |
| PORT | reserved | Set by Dbrij from the service port. Change the port in Settings instead. |
| DBRIJ_FUNCTION_CODE, BUILD_ENV_B64 | reserved | Managed by Dbrij. |
On a service that has deployed before and is not stopped, changing its variables starts a new deploy so the app picks them up. Two people editing the same variables in the browser cannot overwrite each other: a save based on an older copy is refused instead of overwriting the newer one.
npx dbrij env # list the names (values stay hidden)
npx dbrij env add API_URL=https://api.example.com
npx dbrij env rm OLD_FLAG
npx dbrij env pull .env.local # write them to a file (default .env.dbrij)dbrij env add and dbrij env rm change only the names you give, merged on the server, so a change someone else made in the meantime is kept. dbrij env pull writes a file readable only by you; it holds real secrets, so keep it out of git.
A service can also read a Dbrij Secrets project. Link it from the Connections tab of the Secrets project, naming the environment (and optionally a folder). The service then runs with the linked secrets underneath its own variables: on a name both set, the service's own variable wins. The variables tab shows which Secrets project and version the last deploy used. A change to the linked secrets redeploys a running service, and when a deploy with new secrets fails, the service is held at the version that last worked. See the Secrets docs.
A database's connection string goes into an app's variables from Dbrij to Dbrij, without you copying it. The default name is DATABASE_URL for PostgreSQL and MySQL, MONGODB_URI for MongoDB and REDIS_URL for Redis.
Your app listens on the service's port, which Dbrij also passes in the PORT variable. A new service uses 8080 unless you or the scan set another. Read PORT rather than hard coding a number and the two can never disagree.
| Readiness | TCP on the port | A copy receives traffic only once it accepts connections on its port. A slow first boot gets about five minutes before it counts as failed. |
| Liveness | TCP on the port | A copy that stops accepting connections is restarted. It is checked after the first minute, every 20 seconds, and restarted after six misses in a row. |
| Databases | TCP on the engine port | A database is ready only once the engine itself listens. |
| Workers | none | A worker opens no port, so running is its healthy state. |
Because new copies take traffic only when they answer, a deploy replaces the old version without sending visitors to an app that is still starting. Hosting also probes every running web service from outside about every five minutes; those probes feed the uptime charts and automatic rollback (see Logs and rollbacks).
https://<service>.dbrij.appA web service gets a free address on dbrij.app when you switch it on, from the dashboard, from dbrij url, or by answering yes when dbrij deploy asks. It is never created on its own, because creating it issues a certificate for that name. The certificate can take a minute on a brand new name; until then the link shows as securing.
Services created now redirect plain HTTP to HTTPS for every name whose certificate is live. A name joins the redirect only once its certificate works, so visitors are never sent to a certificate error.
Add a domain you own to a web service from its Domains tab. A service takes up to 3 domains; the www companion of a root domain comes free and does not count. Domains bought on Dbrij are set up for you: see the Domains docs.
| Root domain | A record | Host @, value: the address the Domains tab shows. A root domain cannot hold a CNAME, so it takes an A record. |
| Subdomain | CNAME record | Host: the subdomain label (www, app, api.eu), value: your service's address on dbrij.app. |
example.com A @ <the address shown in the Domains tab>
app.example.com CNAME app <service>.dbrij.appTwo level endings such as .com.ng and .co.uk are recognised: acme.com.ng is a root domain and gets the A record.
Hosting checks every few minutes, and on demand when you press check. It asks the domain's own authoritative nameservers rather than a cache, so a record you just fixed counts as soon as it is published. A domain passes when it has a CNAME to your service, or when every A record points at Dbrij. If any A record points somewhere else (a leftover from a previous host, or a registrar's forwarding service), the Domains tab names it, because visitors would land on that server part of the time.
| none | certificate | Not verified yet, so no certificate is requested. |
| issuing | certificate | Verified and the certificate is being issued. A healthy issue takes under a minute. |
| active | certificate | HTTPS is live. |
| failed | certificate | Stuck, with the reason in plain words and a retry. |
A certificate is issued once the service has deployed at least once: until then there is nothing to answer the certificate check, and the domain says to deploy first. It puts itself right after the first deploy.
Adding a root domain also adds its www name, redirecting to the root, so visitors who type www arrive. Any live domain can instead redirect permanently to another live name of the same service, for example www.example.com to example.com or the reverse.
Custom domains are included on every plan. Each plan also caps how many domains can wait connected but not yet attached to a service (see Scaling, plans and limits). A name on dbrij.app cannot be added as a custom domain, and a domain can serve only one service at a time.
Every deployment keeps its build log, and the release command's output when there is one. Variable names never appear in a build log, and values the build prints are replaced with [hidden] (see How builds work).
npx dbrij logs --build # the latest deployment
npx dbrij logs --build a1b2c3d4 # a deployment by the id prefix the CLI printsRuntime logs are what the running service prints, read from its newest copy: up to 1,000 lines. Ask for the previous run to read the output of the copy before the current one, which is where a crash shows its error.
npx dbrij logsOn plans that keep log history, every service's output is collected about every half minute and kept for the plan's number of days. A day can be searched by time range, by level (all, warnings, errors) and by text or a regular expression, up to 1,000 lines a page, and downloaded as plain text one day at a time. Days follow Lagos time. Plans without history show the live output of the newest copy only.
A rollback puts a previous successful build back without rebuilding it. With no argument the CLI goes back to the build before the one running now; give an id prefix to choose.
npx dbrij rollback # the build before this one
npx dbrij rollback a1b2c3d4 # a specific deploymentSwitch on automatic rollback and Hosting puts the previous build back when a deploy takes a healthy site down. It acts only on clear evidence: the site was healthy before the deploy, enough outside probes ran after it, the failure lasted rather than blipped, and a known good build exists. It watches the first 20 minutes after a deploy; after that a failure is treated as an outage, not a bad release.
Restart runs the current build again without rebuilding. Stop takes the service down and start brings it back.
A scheduled job runs a command on a schedule: a nightly cleanup, an hourly report, a reminder email every Monday at nine. Add one in the service's Jobs tab. Web services and background workers can have jobs; databases and static sites cannot.
Each run is its own short lived copy of the service: the version that is live when the run starts, with the service's variables, size and outbound address, but no port and no URL. That is the difference from a scheduler inside your app. A deploy replaces the app's running copies, so a task inside them can be cut off halfway, run twice while the old and new copies overlap, or be missed in the gap. A scheduled job is untouched by a deploy: the next run simply uses the new version, and a run that is going finishes on the version it started with.
Pick every five minutes, hourly, daily at a time, or weekly on a day at a time. For anything else choose Custom and type a cron expression: five parts, for the minute, the hour, the day of the month, the month and the day of the week, where a star means every one. 30 2 * * 1 is 02:30 every Monday and */15 * * * * is every 15 minutes. The form shows the schedule in words and its next three runs as you type. A seconds part and "run at start up" are not supported.
Every job has its own timezone, Africa/Lagos unless you choose another, and the schedule is read on that clock. A run missed while a machine was briefly down still starts if it is less than 5 minutes late.
| Command | text | Run with sh in the service version, from its working folder, with every variable the service has. |
| Time limit | seconds | A run still going after it is stopped and marked Timed out. At least 1 minute. |
| If the last run is still going | choice | Skip the new run (the default: never two at once), or stop the old run and start the new one. |
| Attempts | rule | One. A failed run is reported, never quietly repeated, because a command is not always safe to run twice. |
| History | rule | The last 5 runs that succeeded and the last 5 that failed, with their output, for a day. |
| Run now | action | Starts a run outside the schedule. Refused while a run is going unless the job replaces it. |
Stopping the service pauses its jobs, and starting it lets each one follow its own switch again. A suspended service's jobs are paused too. Deleting the service deletes its jobs. A job does not see a disk attached to the service: give it the data another way, for example through the database.
| Free | plan | No scheduled jobs. The Jobs tab shows how to start on a paid plan. |
| Starter | plan | 3 jobs per service, as often as every 15 minutes, each run up to 30 minutes |
| Pro | plan | 20 jobs per service, as often as every 1 minute, each run up to 2 hours |
| Reserved | plan | 50 jobs per service, as often as every 1 minute, each run up to 6 hours |
Jobs are included in the Starter, Pro and Reserved plan prices. If a plan changes to one that holds fewer, the oldest jobs keep running and the rest pause, with the reason on each, until the plan covers them again.
When a deploy, a restart or a stop replaces a running app, the app is told to stop and gets a moment to finish what it is doing before it is ended. That moment is 30 seconds unless you change it in the service's Settings; paid plans can raise it to 10 minutes. It only helps an app that listens for the stop signal (SIGTERM) and wraps up; one that ignores it is ended at the same moment either way.
Create a database as a service in a project. It starts at once, with its own disk, and is reachable privately by the other services in the project. Each engine has a memory floor its settings will not go below.
The database's page shows its host, port, user, password, database name and a ready made connection URL. Only people who can operate the database see the password. Use the link to an app (see Variables and Secrets) and the URL goes straight into the app's variables.
Public networking is off by default. Switching it on gives the database a public host and port, for a SQL client or an app running on your laptop. It puts the database on the internet protected only by its password, so switch it off when you are done.
| Back up now | manual | A snapshot you take by hand, kept until you delete it. Each plan caps how many you hold; at the cap you delete one first. |
| Nightly | automatic | Off until you switch it on, on plans that include it. The plan sets how many nightly backups are kept. |
| Pre release | automatic | Taken before every release command runs. The newest three are kept per database. |
Backups cover PostgreSQL, MySQL and MongoDB. Redis is a cache and has no dump based backups here. A backup can be downloaded. Switching nightly backups off is always allowed, even when a plan has lapsed.
A restore loads a backup into the same database and replaces what is there: anything written since the backup is lost. Only one load (a restore or an import) runs into a database at a time; another is refused until it finishes or is cancelled. A load in progress shows its progress, and a load that hangs can be cancelled or started again from its stored dump.
For the length of a load, the database is sized up within your plan, and its memory and processor go back afterwards. A size you changed by hand is never overwritten.
If the database restarts in the middle of a load, the connection the loader holds is dead and it would wait forever. A watchdog checks every 30 seconds how long the server has been up; when that is shorter than the load has been running, it stops the load with a clear error instead of leaving it hanging. Start it again from the database's backups list.
On the Reserved plan PostgreSQL runs as three copies with a standby ready, and promotes one on its own if the primary is lost. MySQL, MongoDB and Redis run as a single copy on every plan.
Bring an existing PostgreSQL or MySQL database into a Hosting database of the same engine. Both routes are destructive, exactly like a restore: the target is replaced by what the source holds.
When the old database is reachable over the internet, paste its connection string (postgresql://, postgres://, mysql:// or mariadb://). Hosting connects and copies it across. The engine must match the target. These are refused before anything starts, with the reason:
localhost and loopback addresses, which from Dbrij's side mean Dbrij's own server, not your machine..local, .internal).For any of those, use the route from your machine.
When Dbrij cannot reach the old database (it is on your laptop or a private network), the import dialog gives you one command. It downloads a small script and runs it with your local pg_dump or mysqldump.
curl -fsS "<script address from the dialog>" -o "/tmp/dbrij-import-<id>.sh" && \
DBRIJ_DB_URL="postgresql://USER:PASSWORD@localhost:5432/DATABASE" bash "/tmp/dbrij-import-<id>.sh"curl -fsS "<script address from the dialog>" -o "/tmp/dbrij-import-<id>.sh" && \
DBRIJ_DB_USER=USER DBRIJ_DB_NAME=DATABASE bash "/tmp/dbrij-import-<id>.sh"Copy the exact command from the dialog: it carries your import's own address and token. For MySQL, DBRIJ_DB_HOST and DBRIJ_DB_PORT default to 127.0.0.1 and 3306, and you are asked for the password.
DBRIJ_FOREGROUND=1 to keep it attached.When it says it is done, go back to the dialog and press Load it in.
Each service sets its copies (replicas), memory and CPU in Settings. Changing the number of copies applies live; changing memory or CPU redeploys. The settings never offer a size larger than one machine in your plan's pool can give, and a database engine has a memory floor. A service with a volume runs one copy. On Reserved, a running web service keeps at least two copies on different machines.
Usage is metered on what services actually consume, sampled every five minutes, against the plan's monthly allowance. On paid plans usage past the allowance is billed at the rates below; the free plan stops instead. When the free allowance runs out the app is paused, and it runs again once usage falls back under the allowance.
| Free | Starter | Pro | Reserved | |
|---|---|---|---|---|
| Monthly fee | Free | ₦15,200 / mo | ₦40,000 / mo | ₦150,000 / mo |
| Projects | 1 | 5 | 15 | 50 |
| Services per project | 2 | 8 | 12 | 30 |
| Copies per service | up to 1 | up to 2 | up to 4 | 2 to 12 |
| Memory per service | up to 512 MB | up to 2 GB | up to 4 GB | up to 16 GB |
| CPU per service | up to 0.5 vCPU | up to 2 vCPU | up to 4 vCPU | up to 16 vCPU |
| Disk per database or volume | up to 1 GB | up to 5 GB | up to 20 GB | up to 20 GB |
| Included CPU | 4,300 vCPU minutes | 7,700 vCPU minutes | 21,000 vCPU minutes | 66,000 vCPU minutes |
| Included memory | 5,400 GB minutes | 16,200 GB minutes | 32,400 GB minutes | 120,000 GB minutes |
| Included storage | 1 GB | 25 GB | 150 GB | 1,000 GB |
| Database operations | 100 | 500 | 2,000 | 10,000 |
| Over the allowance | Hard stop | ₦1.65 per vCPU minute, ₦0.55 per GB minute | ₦1.65 per vCPU minute, ₦0.55 per GB minute | ₦1.65 per vCPU minute, ₦0.55 per GB minute |
| Storage over the allowance | Hard stop | ₦800 per GB month | ₦800 per GB month | ₦800 per GB month |
| Managed databases | No | Yes | Yes | Yes |
| Nightly backups kept | None | 3 | 30 | 365 |
| Manual snapshots held | None | 3 | 20 | 100 |
| Connected domains waiting | 3 | 10 | 25 | 100 |
| Company email domains | 1 | 10 | 30 | 100 |
| Log history | Live only | Live only | Live only | 90 days |
| Builder | Standard, 2 vCPU and 4 GB | Standard, 2 vCPU and 4 GB | Larger, 4 vCPU and 8 GB | Larger, 4 vCPU and 8 GB |
| Scheduled jobs per service | None | 3 | 20 | 50 |
| Shutdown window | up to 30 seconds | up to 10 minutes | up to 10 minutes | up to 10 minutes |
| Reserved machines | No | No | No | Yes |
| Uptime commitment | None | None | None | 99.9% |
Database operations are console queries (one each), "what is using this database" reads (three each) and process stops (one each). Paid plans bill each operation past the allowance; the free plan stops.
Plans narrow these; nothing goes past them.
| Projects per account | limit | 50 |
| Services per project | limit | 30 |
| Copies per service | limit | 12 |
| Memory per service | limit | 16 GB |
| CPU per service | limit | 16 vCPU |
| Disk per database or volume | limit | 20 GB |
| Custom domains per service | limit | 3, plus free www companions |
| Variables per service | limit | 200, 400 KB together |
| Packed folder for dbrij deploy | limit | 100 MiB compressed |
When a payment provider, a bank or a partner asks for the address your app calls them from, Hosting has one stable outbound address for that. Your services' outbound calls leave from it.
The address is not printed on every page. Someone who manages the project asks for it and says what it is for (for example, the provider being whitelisted). Dbrij keeps that record, so if the address ever has to move, everyone who whitelisted it is told first. Once released, the project can measure it again from every machine, to confirm calls really leave from that address, and can withdraw its access at any time.
The dbrij package runs with npx dbrij, or install it globally with npm i -g dbrij. Commands that act on a service use the folder's link, so run dbrij link first.
COMMANDS
| dbrij login | account | Sign in by confirming a short code in your browser. |
| dbrij logout | account | Revoke this machine. |
| dbrij whoami | account | Who you are signed in as. |
| dbrij link | setup | Point this folder at a project and an upload service, or create them. |
| dbrij deploy | deploy | Pack, upload, build and roll out this folder, then print the URL. |
| dbrij status | every day | The service state and its five latest deployments. |
| dbrij logs | every day | Runtime logs. --build [id] for a build log. |
| dbrij url | every day | Give the service its public URL, or show the one it has. |
| dbrij open | every day | Open the deployed site in your browser. |
| dbrij ls | every day | Your projects and services. |
| dbrij rollback [id] | every day | Put the previous build back, or the one you name. |
| dbrij env [ls | add | rm | pull] | variables | List names, set KEY=value, remove KEY, or write them to a file. |
| dbrij git setup | Source | Push to Dbrij Source with your Dbrij sign in. No token to paste. |
| dbrij pack | builds | Turn a folder into a container image with Dbrij Pack. See Dbrij Pack builds. |
| dbrij mcp | assistants | Run the local MCP server for an AI coding tool. |
DEPLOY FLAGS
| --no-wait | flag | Queue the deploy and return at once. |
| --url | flag | Give the service a public URL after it deploys, without asking. |
| --no-url | flag | Never create a public URL. A run with no terminal (CI) never creates one unless --url is given. |
| -m, --message "text" | flag | Label the deployment. |
ENVIRONMENT
| DBRIJ_TOKEN | variable | Skip login, for CI. |
| DBRIJ_API_URL | variable | Talk to a different control plane. |
| DBRIJ_DEBUG | variable | Print the full error trace. |
The CLI watches a deploy for up to 25 minutes. Time spent waiting for a free plan build slot does not count. Stopping the watch never stops the deploy.
An AI assistant or coding tool that speaks MCP can deploy and run your apps for you. It acts as you: your permissions, your company role, your plan's limits and the payment check all apply exactly as they would to you. Two servers offer the tools.
| Hosted server | mcp.dbrij.com | Add it as a connector in a chat assistant and sign in with Dbrij. It deploys from GitHub and Dbrij Source repositories, because a chat window has no folder to send. |
| Local server | npx -y dbrij mcp | Runs on your machine beside a coding tool and deploys the folder you are working in. Signed in with your dbrij login. |
{
"mcpServers": {
"dbrij": { "command": "npx", "args": ["-y", "dbrij", "mcp"] }
}
}| whoami | read | The account and permissions the assistant acts with. |
| list_projects | read | Every project you can reach, personal and company, with its services. |
| get_service | read | One service's settings and status. Variable values and database passwords are never shown, only variable names. |
| list_deployments | read | Recent deployments of a service. |
| wait_for_deployment | read | Check on a deployment, waiting for it to finish. |
| build_logs | read | The build and release log of a deployment. |
| runtime_logs | read | What the running service printed, or the run before it. |
| list_domains | read | A service's custom domains, whether DNS and HTTPS work, and the record still needed. |
| plan_and_limits | read | The plan, what it allows and usage this period. |
| list_backups | read | A database's backups, newest first. |
| check_domain | read | Whether a domain is available to buy and its yearly price. |
| get_request | read | Whether you approved, turned down or let expire a request the assistant filed. |
| create_project | change | Create a project, personal or in a company. |
| create_service | change | Add a web service, worker or database. |
| redeploy | change | Build and deploy the latest code (or restart a database). |
| set_env_vars | change | Set or remove variables on a service. |
| link_database | change | Put a database's connection string into an app's variables, without the assistant seeing it. |
| create_public_url | change | Switch on the free dbrij.app address. |
| add_domain | change | Attach a domain you own and return the DNS record to create. |
| verify_domain | change | Check a domain's DNS now. |
| apply_suggested_fix | change | Apply the fix a failed build's diagnosis offers, and deploy again. |
| rollback | change | Put a previous successful build back. |
| restart | change | Restart the running copies without rebuilding. |
The hosted server adds github_status, list_github_repos, scan_github_repo, scan_source_repo and deploy_github_repo. The local server adds scan_folder, which reads a folder the way the Deploy dialog reads a repository, and deploy_folder, which packs and deploys it by the same rules as dbrij deploy.
An assistant can never spend money or delete anything by itself. Changing a plan, buying a domain, resizing a service, deleting a service or project, restoring a backup and removing a domain are filed as requests. You approve or turn them down on Dbrij, from a link and a notification on your phone, never in the chat. A request you do not decide expires after 15 minutes.
| request_plan_change | request | Move to a paid Hosting plan. |
| request_domain_purchase | request | Register an available domain, optionally pointing it at a web service. |
| request_resize | request | Change a service's copies, memory or CPU. |
| request_delete_service | request | Delete a service. You approve by typing its name. |
| request_delete_project | request | Delete a project and every service in it. You approve by typing its name. |
| request_backup_restore | request | Put a database back to one of its backups. |
| request_domain_removal | request | Detach a custom domain from a service. You approve by typing the domain. |
| withdraw_request | request | Take back a request you have not decided yet. |
Variable values and database passwords are never returned to an assistant, only the names of variables. Logs are passed to it marked as untrusted, and it is told never to act on instructions found inside them. When a build diagnosis says to stop, the assistant stops and tells you.
Dbrij Pack turns your code into a container image without a Dockerfile, for teams that run their apps anywhere. Send a folder or a git repository and get an OCI image back: in your space’s own Dbrij registry namespace, or pushed to your own registry. On paid plans every image comes with a list of what is inside it (an SBOM) and provenance, and on Pro the provenance is signed. Pack is the same builder that builds your Hosting services; here it is billed on its own, in naira, as build minutes.
Builds use local package caches: runtimes, packages and base images come from Dbrij’s own copies, so an outage somewhere else does not stop a build. Builds for your Hosting services are included in every Hosting plan and never charged here; Free Hosting has a fair use limit of 300 build minutes a month.
Pack is opening space by space. Until it is open, every route answers: “Dbrij Pack builds are not available yet. They open soon.” The console lives in Hosting, under Builds. A walkthrough is in the Pack guide.
Every route answers a signed in person (the console and dbrij login) or a Dbrij API key. Make a key in Hosting, Builds, API keys: it carries pack:build (start and cancel builds, upload folders) and pack:read (read builds, logs, SBOMs, provenance and signatures), and nothing else. Send it as Authorization: Bearer. Plans, webhooks and the pull credential are managed signed in. Every success body is wrapped in { "success": true, "data": … }, and a refusal carries a message written to be shown to a person.
/v1/pack/uploadspack:buildGet an upload ticket
Where to PUT a .tar.gz of the folder (the same archive dbrij deploy makes). PUT the bytes to uploadUrl before it expires, then create the build with sourceKey.
curl -X POST https://api.dbrij.com/api/v1/pack/uploads \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": {
"uploadUrl": "https://…",
"sourceKey": "pack/uploads/…tar.gz",
"maxBytes": 524288000,
"expiresAt": "2026-11-08T10:15:00.000Z"
}
}/v1/pack/buildspack:buildStart a build
Build an uploaded folder (sourceKey) or a git repository over https (gitUrl). Returns the build at once, queued; follow it with the build and its log.
PATH / BODY PARAMETERS
| tag* | string | The image name and tag in your space’s namespace, like web:1.4.0. Lowercase, a tag after a colon, no digest. |
| sourceKey | string | An uploaded folder, from the upload ticket. Give this or gitUrl. |
| gitUrl | string | A git repository over https. |
| gitRef | string | Branch or tag; the default branch when left out. |
| gitToken | secret ref | A token for a private repository, read from Dbrij Secrets at build time: { "project": "web", "environment": "production", "key": "GHCR_TOKEN" }. |
| rootDir | string | The folder inside the source to build, for a repository that holds several apps. |
| dockerfilePath | string | Build with this Dockerfile, relative to the source root. |
| installCommand, buildCommand, startCommand | string | Override what the build works out from your code. |
| staticOutputDir | string | Serve this folder as a static site after the build. |
| push | string | Push to your own registry instead, like ghcr.io/acme/web:1.4.0. Name the registry. |
| pushUsername | string | The user name for that registry. |
| pushCredential | secret ref | Its password or token, read from Dbrij Secrets. The value never leaves Dbrij. |
| buildSecrets | secret ref[] | Build variables from Dbrij Secrets, passed to the build as secret mounts, never as build arguments. |
| builder | "standard" | "large" | The large builder (Pro): twice the CPU and memory, each minute counted twice. |
| label | string | A label for the build list, such as a commit title. |
| trigger | string | Who asked: cli, api, action, source_ci or web. Set by the command line and the Action. |
curl -X POST https://api.dbrij.com/api/v1/pack/builds \
-H "Authorization: Bearer $DBRIJ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"gitUrl":"https://github.com/acme/web.git","gitRef":"main","tag":"web:1.4.0"}'{"gitUrl":"https://github.com/acme/web.git","gitRef":"main","tag":"web:1.4.0"}{
"success": true,
"data": {
"id": "6f1c2a4e-9b0d-4c6e-a1f2-3d4b5c6d7e8f",
"status": "succeeded",
"source": "git",
"gitUrl": "https://github.com/acme/web.git",
"gitRef": "main",
"rootDir": null,
"target": "dbrij",
"imageRef": "registry.dbrij.app/pack-3f2a9c1b/web:1.4.0",
"digest": "sha256:4f1c9a2b7d0e…",
"builder": "standard",
"stack": "node/next",
"path": "automatic",
"trigger": "action",
"label": "Add the pricing page",
"createdAt": "2026-11-08T10:00:00.000Z",
"startedAt": "2026-11-08T10:00:04.000Z",
"finishedAt": "2026-11-08T10:02:41.000Z",
"seconds": 157,
"billedMinutes": 3,
"error": null,
"diagnosis": null,
"hasSbom": true,
"hasProvenance": true,
"hasDockerfile": true,
"signature": {
"by": "dbrij",
"keyId": "dbrij-pack-2026",
"fingerprint": "9c1e…",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\n…",
"algorithm": "ecdsa-p256-sha256",
"signedAt": "2026-11-08T10:02:42.000Z"
},
"createdBy": { "id": "…", "name": "Ada" }
}
}/v1/pack/buildspack:readList builds
The space’s builds, newest first, a page at a time. Pass next as before for the next page.
QUERY PARAMETERS
| status | string | queued, building, succeeded, failed or cancelled. |
| before | string | The next value from the previous page. |
curl -X GET https://api.dbrij.com/api/v1/pack/builds \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": { "builds": [ { "id": "6f1c…", "status": "building", … } ], "next": "6a0b…" }
}/v1/pack/builds/:idpack:readGet a build
Where the build stands, what it made and, when it failed, the diagnosis: what went wrong and what to try.
curl -X GET https://api.dbrij.com/api/v1/pack/builds/:id \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": {
"id": "6f1c2a4e-9b0d-4c6e-a1f2-3d4b5c6d7e8f",
"status": "succeeded",
"source": "git",
"gitUrl": "https://github.com/acme/web.git",
"gitRef": "main",
"rootDir": null,
"target": "dbrij",
"imageRef": "registry.dbrij.app/pack-3f2a9c1b/web:1.4.0",
"digest": "sha256:4f1c9a2b7d0e…",
"builder": "standard",
"stack": "node/next",
"path": "automatic",
"trigger": "action",
"label": "Add the pricing page",
"createdAt": "2026-11-08T10:00:00.000Z",
"startedAt": "2026-11-08T10:00:04.000Z",
"finishedAt": "2026-11-08T10:02:41.000Z",
"seconds": 157,
"billedMinutes": 3,
"error": null,
"diagnosis": null,
"hasSbom": true,
"hasProvenance": true,
"hasDockerfile": true,
"signature": {
"by": "dbrij",
"keyId": "dbrij-pack-2026",
"fingerprint": "9c1e…",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\n…",
"algorithm": "ecdsa-p256-sha256",
"signedAt": "2026-11-08T10:02:42.000Z"
},
"createdBy": { "id": "…", "name": "Ada" }
}
}/v1/pack/builds/:id/logspack:readRead the log
The whole log so far, in our wording: machine lines left out, variable names left out, and any variable value in the output hidden. While live is true the build is still running; ask again every two or three seconds until it is false.
curl -X GET https://api.dbrij.com/api/v1/pack/builds/:id/logs \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": { "logs": "==> Building web:1.4.0\n==> 12 build variables passed to the build. Names and values are hidden.\n…", "live": true }
}/v1/pack/builds/:id/sbompack:readGet the SBOM
The list of what is inside the image, as an SPDX JSON document. Paid plans only; hasSbom says whether the build has one.
curl -X GET https://api.dbrij.com/api/v1/pack/builds/:id/sbom \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": { "spdxVersion": "SPDX-2.3", "packages": [ { "name": "next", "versionInfo": "15.0.3", "licenseConcluded": "MIT" }, … ] }
}/v1/pack/builds/:id/provenancepack:readGet the provenance
An in toto statement with SLSA provenance: the builder, what went in (sources, base images) with their digests, and when it ran.
curl -X GET https://api.dbrij.com/api/v1/pack/builds/:id/provenance \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": { "_type": "https://in-toto.io/Statement/v0.1", "predicateType": "https://slsa.dev/provenance/v0.2", "subject": [ … ], "predicate": { "builder": { "id": "…" }, "materials": [ … ] } }
}/v1/pack/builds/:id/dockerfilepack:readGet the recipe as a Dockerfile
What the build did, as a Dockerfile you can keep and build anywhere.
curl -X GET https://api.dbrij.com/api/v1/pack/builds/:id/dockerfile \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": { "dockerfile": "FROM …\nRUN …" }
}/v1/pack/builds/:id/signaturepack:readGet the signature bundle
The signed payload (base64 JSON that names the image digest and the attestation digests), the DER ECDSA signature over its SHA 256 (base64), and the public key that checks it.
curl -X GET https://api.dbrij.com/api/v1/pack/builds/:id/signature \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": {
"by": "dbrij",
"keyId": "dbrij-pack-2026",
"fingerprint": "9c1e…",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\n…",
"algorithm": "ecdsa-p256-sha256",
"signedAt": "2026-11-08T10:02:42.000Z",
"payload": "eyJpbWFnZSI6…",
"signature": "MEUCIQ…"
}
}/v1/pack/builds/:id/cancelpack:buildCancel a build
Stops a queued or running build. Only the minutes it ran are counted.
curl -X POST https://api.dbrij.com/api/v1/pack/builds/:id/cancel \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": { "id": "6f1c…", "status": "cancelled", … }
}/v1/pack/accountpack:readThe space’s plan and usage
Whether the service is open, the plan, minutes used this period, builds running now, whether a card is verified, and the space’s registry namespace.
curl -X GET https://api.dbrij.com/api/v1/pack/account \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": {
"available": true,
"buildNodeReady": true,
"plan": "pack_starter",
"planName": "Starter",
"status": "active",
"interval": "monthly",
"autoRenew": true,
"currentPeriodEnd": "2026-12-08T00:00:00.000Z",
"graceUntil": null,
"pinnedPriceNgnMinor": 450000,
"usage": { "minutes": 312, "includedMinutes": 1000, "overMinutes": 0, "accruedOverageNgnMinor": 0, "periodStart": "…", "periodEnd": "…", "builds": 41, "failed": 3, "running": 1 },
"cardVerified": true,
"namespace": "registry.dbrij.app/pack-3f2a9c1b",
"canManage": true
}
}/v1/pack/planspack:readThe plans
Every plan with its price in kobo, minutes, builds at a time and what it includes. Prices set by Dbrij here win over any copy of them.
curl -X GET https://api.dbrij.com/api/v1/pack/plans \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": [ { "id": "pack_free", "name": "Free", "priceNgnMinor": 0, "includedMinutes": 100, … }, … ]
}/v1/pack/checkoutsigned inChoose a plan
Starts the checkout for a plan, in naira. With useSavedCard the saved card is charged on the spot and charged is true; otherwise open authorizationUrl. The owner, or a finance manager in a company.
PATH / BODY PARAMETERS
| plan* | string | pack_starter or pack_pro. |
| interval | "monthly" | Monthly. |
| useSavedCard | boolean | Charge the saved card, with no redirect. |
curl -X POST https://api.dbrij.com/api/v1/pack/checkout \
-H "Authorization: Bearer $DBRIJ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"plan":"pack_starter","useSavedCard":true}'{"plan":"pack_starter","useSavedCard":true}{
"success": true,
"data": { "authorizationUrl": null, "reference": "…", "charged": true }
}/v1/pack/renewalsigned inStop or keep renewing
renew false cancels: the plan is not charged again and stays on until its paid period ends. renew true takes that back.
curl -X POST https://api.dbrij.com/api/v1/pack/renewal \
-H "Authorization: Bearer $DBRIJ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"renew":false}'{"renew":false}{
"success": true,
"data": { "plan": "pack_starter", "autoRenew": false, … }
}/v1/pack/pull-credentialssigned inThe pull credential
The read only login for the space’s namespace, without its password; null when none has been made.
curl -X GET https://api.dbrij.com/api/v1/pack/pull-credentials \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": { "registry": "registry.dbrij.app", "namespace": "registry.dbrij.app/pack-3f2a9c1b", "username": "robot$pack-3f2a9c1b+pull", "createdAt": "…" }
}/v1/pack/pull-credentialssigned inMake or rotate the pull credential
A new password for the read only login. It is returned once; the old one stops working.
curl -X POST https://api.dbrij.com/api/v1/pack/pull-credentials \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": { "registry": "registry.dbrij.app", "namespace": "…", "username": "…", "password": "…", "createdAt": "…" }
}/v1/pack/webhookssigned inList webhooks
Where finished builds are posted, with failures so far and the last error.
curl -X GET https://api.dbrij.com/api/v1/pack/webhooks \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": [ { "id": "…", "url": "https://example.com/hooks/dbrij", "events": ["build.succeeded", "build.failed"], "enabled": true, "failures": 0, "lastError": null, "createdAt": "…" } ]
}/v1/pack/webhookssigned inAdd a webhook
An https address and the events to send; every event when events is left out. The signing secret is returned once.
PATH / BODY PARAMETERS
| url* | string | An https address. |
| events | string[] | build.succeeded, build.failed, build.cancelled |
curl -X POST https://api.dbrij.com/api/v1/pack/webhooks \
-H "Authorization: Bearer $DBRIJ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/hooks/dbrij","events":["build.succeeded","build.failed"]}'{"url":"https://example.com/hooks/dbrij","events":["build.succeeded","build.failed"]}{
"success": true,
"data": { "id": "…", "url": "https://example.com/hooks/dbrij", "events": ["build.succeeded", "build.failed"], "enabled": true, "failures": 0, "lastError": null, "createdAt": "…", "secret": "whsec_…" }
}/v1/pack/webhooks/:idsigned inRemove a webhook
Nothing more is sent to it.
curl -X DELETE https://api.dbrij.com/api/v1/pack/webhooks/:id \
-H "Authorization: Bearer $DBRIJ_API_KEY"Returns 204 (no body).
/v1/pack/signing-keypublicDbrij’s signing key
Dbrij’s public key for every image it signs, so you can check a signature without signing in.
curl -X GET https://api.dbrij.com/api/v1/pack/signing-key \
-H "Authorization: Bearer $DBRIJ_API_KEY"{
"success": true,
"data": { "keyId": "dbrij-pack-2026", "fingerprint": "9c1e…", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n…", "algorithm": "ecdsa-p256-sha256" }
}A build is queued, then building, then succeeded, failed or cancelled. Ask for the log every two or three seconds while live is true; the console does the same every 2.5 seconds. A failed build carries a diagnosis: one sentence on what went wrong, whether it was on our side, and what to try.
while true; do
curl -s -H "Authorization: Bearer $DBRIJ_TOKEN" https://api.dbrij.com/api/v1/pack/builds/$ID/logs > log.json
jq -r .data.logs log.json | tail -n 5
[ "$(jq -r .data.live log.json)" = "false" ] && break
sleep 3
doneAdd a webhook in Hosting, Builds, Webhooks and pulls, or with the API. When a build ends, Dbrij posts its event with the whole build as JSON. Each delivery carries X-Dbrij-Signature: sha256=…, an HMAC SHA 256 of the raw body with the webhook’s secret, like every Dbrij webhook. Check it before you trust the body.
build.succeededThe image is pushed; data.digest is set.{ "type": "build.succeeded", "createdAt": "…", "data": { "id": "6f1c…", "status": "succeeded", "imageRef": "…", "digest": "sha256:…", … } }build.failedThe build failed; data.diagnosis says why.{ "type": "build.failed", "createdAt": "…", "data": { "id": "6f1c…", "status": "failed", "diagnosis": { "title": "…", "side": "yours", … }, … } }build.cancelledSomebody cancelled it, or it ran past the plan’s time limit.{ "type": "build.cancelled", "createdAt": "…", "data": { "id": "6f1c…", "status": "cancelled", … } }import { createHmac, timingSafeEqual } from 'crypto';
function verify(rawBody, header, secret) {
const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex');
return header.length === expected.length && timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}dbrij pack is part of the dbrij command line. Sign in once with dbrij login, or set DBRIJ_TOKEN to a key in CI. The folder is packed with the same rules as dbrij deploy: what .gitignore and .dbrijignore leave out stays out.
COMMANDS
| dbrij pack build [folder] --tag web:1.0.0 | on Dbrij | Upload the folder, build it and wait, with the log in your terminal. |
| dbrij pack status <id> | on Dbrij | Where a build stands. --json for the build as JSON. |
| dbrij pack logs <id> | on Dbrij | The build log so far. --follow waits for the end. |
| dbrij pack dockerfile --build <id> | on Dbrij | A finished build’s recipe as a Dockerfile. --out FILE to save it. |
| dbrij pack build [folder] --tag web:dev --local | this machine | Build into this machine’s images with the open source dbrij-pack tool and your own BuildKit or Docker. |
| dbrij pack plan [folder] | this machine | How the folder would be built. --json for the plan file. |
| dbrij pack dockerfile [folder] | this machine | The recipe as a Dockerfile you can keep. |
BUILD FLAGS
| --push ghcr.io/acme/web:1.0.0 | flag | Push to your own registry instead. |
| --push-username NAME | flag | The user name for that registry. |
| --push-credential project/env/KEY | flag | Its password or token, from Dbrij Secrets. |
| --git-url URL, --git-ref REF, --git-token project/env/KEY | flag | Build from git instead of a folder. |
| --root-dir apps/web | flag | The folder inside the source to build. |
| --dockerfile path/Dockerfile | flag | Build with your own Dockerfile. |
| --install CMD, --build-cmd CMD, --start-cmd CMD | flag | Override the commands the build works out. |
| --secret project/env/KEY | flag | A build variable from Dbrij Secrets, as a secret mount. Repeat it. |
| --large | flag | The large builder (Pro). |
| --org ID | flag | Build in a company space. |
| --label TEXT | flag | A label for the build list. |
| --no-wait | flag | Start the build and return. |
| --cancel-on-exit | flag | Ctrl C cancels the build, not only the watching. |
| --json | flag | Print the finished build as JSON on stdout; everything else goes to stderr. |
Local builds with --local run the open source dbrij-pack tool on your machine against your own BuildKit (or Docker). They fetch runtimes and packages from their public sources, not from the Dbrij package caches, and cost no build minutes. Set DBRIJ_PACK_BIN to where the tool is, and BUILDKIT_HOST to your BuildKit.
The Dbrij Pack Action runs dbrij pack build in your workflow and hands back the image reference and digest. It is published by Dbrij from its GitHub organisation as DbrijHQ/pack-action.
jobs:
image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: pack
uses: DbrijHQ/pack-action@v0
with:
token: ${{ secrets.DBRIJ_TOKEN }}
tag: web:${{ github.sha }}
- run: echo "Built ${{ steps.pack.outputs.image }}@${{ steps.pack.outputs.digest }}"INPUTS
| token | required | A Dbrij API key with pack:build and pack:read. Keep it in your repository secrets. |
| tag | required | The image name and tag in your space’s namespace, like web:1.0.0. |
| folder | default . | The folder to build, relative to the workspace. |
| push | optional | Push to your own registry instead. Name the registry. |
| push-username | optional | The user name for that registry. |
| push-credential | optional | Its password or token in Dbrij Secrets, as project/environment/KEY. |
| root-dir | optional | The folder inside the source to build. |
| dockerfile | optional | A Dockerfile to build with, relative to the folder. |
| large | default false | The large builder (Pro). Each minute counts twice. |
| org | optional | The company id, to build in a company space. |
| cli-version | optional | The version of the dbrij command line to run. |
OUTPUTS
| image | string | The image reference the build pushed. |
| digest | string | The pushed image’s digest (sha256:…). |
| build-id | string | The build’s id, for the API and the console. |
| sbom-url | string | Where the API serves the SBOM, when your plan includes one. Ask for it with the same key. |
In a Source CI pipeline, add a step that builds the commit. Put a key with pack:build and pack:read in the pipeline’s secrets as DBRIJ_TOKEN.
npx --yes dbrij pack build . --tag web:$DBRIJ_CI_SHAOn paid plans every image gets an SBOM: an SPDX JSON list of every package inside it, with versions and licences. Provenance is an in toto statement in the SLSA format: which builder ran, what went in with their digests, and when. Both are attached to the image and served by the API; the console shows them under a build and downloads them as JSON.
Pack builds pass build variables as secret mounts, so no value is ever recorded in provenance or in an image layer. A build from your own Dockerfile receives its variables as build arguments, so its provenance records build arguments only in a minimal form. Use secret mounts for anything sensitive.
A signed build has a signature bundle: a payload that names the image digest and the attestation digests, an ECDSA P 256 signature over the payload’s SHA 256, and the public key. Check it with standard open tools:
# Save the three files (the Signature tab of a build downloads them, or decode the API's bundle).
jq -r .data.payload bundle.json | base64 -d > payload.json
jq -r .data.signature bundle.json | base64 -d > sig.der
jq -r .data.publicKeyPem bundle.json > key.pem
# The signature. It prints "Verified OK".
openssl dgst -sha256 -verify key.pem -signature sig.der payload.json
# The payload must name the image's digest, or the signature is not about this image.
grep -c "sha256:<the image digest>" payload.jsonThen check the key is Dbrij’s: GET /v1/pack/signing-key returns Dbrij’s public key and its fingerprint (SHA 256 of the key’s DER), with no sign in. A build signed with your own key from Dbrij Secrets carries your key instead.
A build counts the seconds it ran as minutes, rounded up; the large builder counts each minute twice. Paid plans keep building past the allowance and bill the extra minutes when the plan renews; the free plan stops. Prices are in naira, and the price you chose a plan at is pinned: renewals never charge more for it. Cancel stops the renewal, and the plan stays on until its paid period ends.
| Free | Starter | Pro | |
|---|---|---|---|
| Monthly fee | Free | ₦4,500 / mo | ₦15,000 / mo |
| Build minutes included | 100 | 1,000 | 4,000 |
| Past the allowance | Stops | ₦4 a minute | ₦4 a minute |
| Builds at a time | 1 | 2 | 4 |
| Longest build | 20 minutes | 60 minutes | 60 minutes |
| Largest builder | Standard | Standard | Large |
| SBOM | No | Yes | Yes |
| Signed provenance | No | No | Yes |
| Your own signing key | No | No | Yes |
| Verified card needed | Yes | Yes | Yes |
| Time per build | limit | 20 minutes on Free, up to 60 on paid plans. A build past it is stopped. |
| Builds at a time | limit | Per space, by plan: Free 1, Starter 2, Pro 4. |
| Machines | limit | Images are built for amd64 machines only for now. |
| Free plan | limit | A verified card before the first build, and a hard stop at the monthly minutes. |
Dbrij Pack’s open source parts and their licences are listed on the third party notices page.
Every SDK and package for Hosting, with what it does, how to install it and the smallest working use. The whole catalogue, for every product, is on the apps page.
The Dbrij command line: deploy to Hosting from any directory, run your app with its Dbrij Secrets, and cut Ship releases from your CI.
Command line · TypeScript · npm · Runs on Node 20+
npm i -g dbrijnpm i -g dbrijdbrij login # confirm the code in your browserdbrij link # point this directory at a servicedbrij deploy # ship itBuild a container image on Dbrij from a GitHub workflow, with no Dockerfile, and get its reference and digest back as outputs.
Plugin · Shell · GitHub Actions, published by Dbrij · Runs on GitHub Actions, Node 20+ on the runner
uses: DbrijHQ/pack-action@v0- uses: actions/checkout@v4- id: pack uses: DbrijHQ/pack-action@v0 with: token: ${{ secrets.DBRIJ_TOKEN }} tag: web:${{ github.sha }}Dbrij is Nigeria’s company operating system: the first Nigerian built platform to put team chat, video meetings, email, HR, tax compliant payroll, customer support, marketing, analytics and cloud hosting in one product on one subscription.