Deployments
Connecting a repository, the production branch, and the build folder in a monorepo.
Deployments
A repository is connected once you register the webhook address from the console's deployments screen on GitHub and push for the first time. After that, every push is built and deployed.
list_apps connected repositories, production branch, folder to build
update_app change the production branch, folder to build, framework preset, build/output/install settings, and who the server runs as (run_as)
delete_app delete one app: its addresses go and its deployments are deleted (the app name in confirm)- A push to the production branch changes the project's main address. Other branches go to preview addresses named after the branch.
- For a monorepo, put the app's folder (for example
apps/web) inroot_directory. The whole repository is.. - The framework is detected at build time. If detection is wrong, choose a preset with
framework, and overridebuild_command,output_directoryorinstall_commandif needed (the same values as the console's build settings). null is the preset default; an empty command skips that step. - A background worker (a queue consumer, a chat bot, a connection held open to an exchange: a server with no web requests) sets
"worker": trueinblackwall.jsonand its command in package.json'sstart. It need not open a port; it is kept running and restarted if it exits. Web requests to it get a 404. - GPU jobs and GPU servers: on Pro and up, rent a GPU by the second.
create_gpu_jobruns a command in a public image to its end (training, a batch) and lets the GPU go when it ends; results last only if the job uploads them somewhere, such as the project's storage.get_gpu_jobshows its status and the end of its output,cancel_gpu_jobstops it.create_gpu_serverhosts a model, called with the secret key athttps://<ref>.<zone>/gpu/v1/servers/<name>/: the first request starts it (503 meanwhile) and it stops after its idle minutes.stop_gpu_serveranddelete_gpu_serverstop or remove it.create_gpu_volumemakes GPU storage in one data center; give it to a job or server asvolumeand it is mounted at/workspace, so a model is downloaded once (billed by the GB-month while it exists;delete_gpu_volumedeletes it).region(auto, asia, us, eu) chooses where to rent; with storage, the GPU is rented in its data center. The closest to Korea is AP-JP-1 (Japan). The image, command, environment variables and stored files are processed in RunPod's data centers. Prices and how many run are inlist_gpu. From ₩4,500 an hour for an RTX 4090, billed by the second from when the GPU is rented until it is let go, image download included. - MySQL databases (WordPress):
create_mysql_databasemakes a MariaDB 11.4 database and its own login (usually within a minute). Withapponly that app gets it; without, it is the whole project's (while it is the only one, every app gets it).bind_mysql_databasechanges which app gets it. That app's servers start withMYSQL_URL,MYSQL_HOST,MYSQL_PORT,MYSQL_USER,MYSQL_PASSWORD,MYSQL_DATABASEand, as the official WordPress image reads them,WORDPRESS_DB_HOST(host:port),WORDPRESS_DB_USER,WORDPRESS_DB_PASSWORD,WORDPRESS_DB_NAME. Never in a build, and a variable saved under the same name wins. Previews get the same database. The address is reachable only from apps on this server.get_mysql_connectionshows how to connect;list_mysql_databaseslists them with the plan's limit (Free 1, Pro 10, Enterprise 50). Backed up every night;create_mysql_backup,list_mysql_backupsandrestore_mysql_backupback up now and put one back (the state just before is backed up first).delete_mysql_databasedeletes the database, its login and every backup. Deleting and restoring take the database name exactly inconfirm. REST:/mysql,/mysql/<name>,/mysql/<name>/connection,/mysql/<name>/backups,/mysql/<name>/restore. - Phone calls and websockets: a server deployment takes websockets. Point a Twilio number's voice webhook at
https://<address>/voiceand the call's audio streams in live (starter:examples/phone-voicein the repository). While a connection is open the server is left out of the idle stop and of making room, so a long call is not cut. Keep a main number on the production deployment: waking a stopped server makes the first call a few seconds late. - Server memory is 512 MB (one CPU) by default; choose 1024, 2048 or 4096 MB with
set_server_memory(or the console's Deployments → Build settings; the current size and a month's cost are inget_server_memory). Above 1024 MB a server gets two CPUs. The memory held is metered by the hour asruntime_gb_hour. Each plan sets the largest size it allows. Servers at production and branch addresses always run, requests or not (minimum one instance; there is no switch for it), so the month inget_server_memoryis what one server costs a month. - Concurrent builds: how many of this project's builds run at once, 1 to 20 with
set_concurrent_builds, or null for no limit (the console's Deployments → Build settings, right below server memory; the current value is inget_concurrent_builds). Builds over the limit wait in the queue, and a waiting build is not billed for build minutes. - Dockerfile: a project folder with a Dockerfile and no package.json (Python, Go, any language) is built from that Dockerfile and run as an image. A repository that also has a package.json asks for the image by choosing the
dockerpreset or"framework": "docker"in blackwall.json. It starts with the image's CMD and listens on the port the image EXPOSEs (the lowest TCP port, or 3000 if none); set another withportonupdate_app. Whatever USER the image names, it runs as an unprivileged user (uid 10001) on a read-only file system. It can write to/tmp(64 MB), to/run,/var/run/apache2and/var/lock/apache2(16 MB each, empty after a restart), to the paths listed in blackwall.json's"writablePaths"(up to 8, 16 MB each), and to its volumes. Keep files that must last on a volume (below). It may listen on a port below 1024, such as 80. An image that must start as root, like the official WordPress image, needs "Run as the image user" turned on in the build settings (run_as: "image"on update_app). It then runs as the image's USER, root included, inside a gVisor sandbox, so even as root it cannot reach other projects. On a server without gVisor, turning it on is refused with a message saying so. Build-time variables reach the build as--build-argand stay in the image's history, so keep secrets in the server's variables. Each build step gets 2 GB and 2 CPUs, a build at most 45 minutes, and an image at most 4 GB. /data: a server that is not a Dockerfile build (Node and the like) can write to/dataas it is, because SDKs written for Railway and Fly keep their cache and tokens there. It holds up to an eighth of the server's memory (16 MB to 256 MB) and is empty after a restart. To keep what is in it, attach a volume at/data(below), which takes its place.- Volumes are disk that stays when a server restarts or a new deployment goes out. Add one to an app's production servers with
create_volume(WordPress:/var/www/html), see them withlist_volumes, grow one withresize_volume(it cannot shrink), and remove one withdelete_volume(its files and backups are gone and it cannot be undone, so confirm takes its path).create_volume_backuppacks the files and keeps them 30 days;restore_volume_backupputs one back (the files it replaces are backed up for 7 days first). A volume is 1 to 500 GB and its size is a hard cap: past it, writes fail. The plan sets what a project's volumes may hold together (Free 1 GB, Pro 50 GB). Previews, and older deployments production no longer serves, get none. Adding or removing one restarts the servers within a minute. The console has the same under Deployments → Build settings. - Changed settings apply from the next push. Only owners and admins can change them.
Git connection: importing, private repositories and GitLab
The same things as Deployments → Git connection in the console.
list_git_access connected repositories (connected), GitHub accounts, saved tokens (last four characters)
list_importable_repositories find repositories the GitHub App can see (query searches all, refresh asks again)
import_repository connect a repository and start its first deployment (with build settings and dotenv)
disconnect_repository disconnect one repository: pushes stop deploying, history stays
set_checks_on_server Run checks on One Server: a GitHub repository's Actions jobs on One Server's machines (on/off)
add_repository connect a repository before the first push (github: owner/name, gitlab: group/name)
set_repo_token a token to fetch a private repository (gitlab_base for self-hosted GitLab)
remove_repo_token delete a token
link_github_app link the GitHub account another project of the organisation already linked
unlink_github_app disconnect one GitHub account (App installation), or all of themConnecting a GitHub account needs a person to confirm it on GitHub, so it can only be done in the console under Deployments → Git connection. Importing after that works through MCP.
If a private repository's build fails at the fetch step, start with list_git_access. Only owners and admins can change any of this.
Import from another server
The same as Import from another server under the organisation in the console. Source accounts (Supabase, Vercel, PostgreSQL) are connected once in the console, so a token is never pasted into a chat. Supabase connects with [Sign in with Supabase]: press Authorize, nothing to copy.
import_sources connected source accounts, their projects, and imports so far
start_import start an import (one split in the console, or connection+project with one new project per group)
get_import each destination's progress by step, what is not moved and why
copy_auth_from_import copy a Supabase project's sign-in settings (social providers, redirect addresses) into a project here
set_vault_project_keys write this project's own address and secret key to its vault (they move inside the server)
copy_vault_secrets_from_project copy another project's vault secrets, values included (values move inside the server)
copy_jobs_from_project copy another project's scheduled jobs, switched off
copy_auth_from_project copy another project's sign-in settings into this one (secrets move inside the server)
copy_storage_from_project copy another project's buckets and files into this project (same size: passed over)
copy_storage_from_import copy a Supabase project's buckets and files into a project here (same size: passed over)A Supabase source needs its session pooler connection string in start_import's address. It is used for that run only and then deleted. Scheduled jobs arrive switched off. Over REST: GET /v1/imports/sources, POST /v1/imports {org, import, connection, project, address} and GET /v1/imports/<id>.
To move only the sign-in settings into a project that already exists, use copy_auth_from_import. Secrets are read from Supabase with the connected account and stored, never put in the answer. See what would move with dry_run first, and afterwards register the answer's callback_url in each provider's console. Sign-in fails until it is registered. Over REST: POST /v1/projects/<ref>/config/auth/copy-from-import {connection, project, providers, dry_run}.
To move only the files, use copy_storage_from_import. A bucket missing here is made with Supabase's public flag and limits, and a file already here with the same size is passed over. One call copies up to 200 files within 45 seconds; when files remain, call again with the answer's next until done is true. The Supabase key is used inside the server only and never put in the answer. Bucket access rules are not copied. Over REST: POST /v1/projects/<ref>/storage/copy-from-import {connection, project, buckets, rename, dry_run, next, max_files}.
Deploying without a push
redeploy rebuild the same commit (when you added environment variables later)
deploy_commit deploy a specific commit
promote_deployment a finished preview build, to production
rollback_deployment production, back to an earlier production deployment (no rebuild; holds production)
create_deploy_hook an address that, when called, builds the branch's latest commit (CMS publishing, etc.)
list_deploy_hooks those addresses
remove_deploy_hook delete an addressIf you changed environment variables, you need a redeploy. Values baked into a build change only when it is rebuilt. Promoting a preview to production rebuilds it with the production environment variables. The preview build is not reused as it is. Only owners and admins can deploy to production.
Deploying without a repository
deploy_files send files (path to content), build and deploy them (up to 3MB in total; more: create_source_upload_url → deploy_source)
deploy_source deploy an archive already uploaded (source)
create_source_upload_url an address to PUT a large archive to without the token (1 hour)- They go through the same build as a pushed commit. With a package.json the framework is detected and built; with only
index.htmlit is served as it is. - With
prebuilt: truenothing is built and the files are served as sent (an already builtdist/). targetispreview(the default) orproduction. A preview address comes frombranch(previewby default). A project with no app gets asiteapp.- For a large site use
oneend deploy(packs the folder and uploads it) orPOST /deployments/sources(body: .zip, .tar, .tar.gz, up to 50MB), then deploy thesourceit returns. - With tools alone, get an address with
create_source_upload_url, PUT the archive to it (curl -X PUT --data-binary @site.zip '<url>'), and calldeploy_sourcewith thesourcein the answer. The address works for that project for 1 hour, with the same size limit and checks asPOST /deployments/sources. Over REST it isPOST /v1/projects/<ref>/deployments/sources/upload-urls. node_modulesand.gitare left out. Paths or links pointing outside the folder, and archives that would be too large unpacked, are refused.
More build settings, system variables, deployment security
get_build_settings per app: development command, Node.js version, ignored build step, production first, required checks
set_build_dev_settings development command (oneend dev) and Node.js version (18 | 20 | 22 | 24)
set_ignored_build_step which pushes are built (automatic | every | production | preview | folder | command)
set_production_first production builds first in the queue
set_git_checks required GitHub checks, Git LFS, verified commits only
set_expose_system_env set or leave out system variables such as BLACKWALL_ENV and BLACKWALL_URL
set_directory_listing list the files of a folder with no index.html
get_deployment_security who sees build logs and output, fork protection, OIDC
set_deployment_security change those (what is left out stays)The framework, the build, install and output commands and the build machine are update_app. Only owners and admins can change any of these.
Deployment retention and restoring
get_deployment_retention how long each kind of deployment is kept (days in force, the project's number, the plan default)
set_deployment_retention change it (null for the plan default; project admins)
list_deleted_deployments deployments deleted in the last 30 days, and until when each can be restored
delete_deployment delete a deployment (restorable for 3 days)
restore_deployment restore a deleted deployment- Plan defaults: Free keeps every kind 30 days. Pro and Enterprise keep canceled 30 days, failed 90, preview 180 and production 1 year (365). A project's own number wins.
- Kept whatever the period: the 10 newest deployments, the 20 newest ready production deployments, the 20 newest ready deployments that are not production, and anything production, a branch or a domain is serving now (including each branch's latest preview).
- A deployment you delete, or one deleted because its period ended, can be restored with
restore_deploymentfor 3 days. Meanwhile itsdpl-…address answers 410; after 3 days its files and build log are removed and it cannot come back. - Over REST:
GET·PUT /v1/projects/<ref>/deployment-retention,GET /v1/projects/<ref>/deployments/deleted,DELETE /v1/projects/<ref>/deployments/<id>,POST /v1/projects/<ref>/deployments/<id>/restore. In the CLI:oneend deployments retention,oneend deployments deleted,oneend deployments rm,oneend deployments restore.
Addresses, waiting and the security check
- The tools that make a deployment (
deploy_files,deploy_source,deploy_commit,redeploy,promote_deployment), andget_deployment,list_deploymentsandrollback_deployment, answer with its addresses.urlis that deployment's owndpl-…address,production_urlthe production address,preview_urlits branch's preview address. With preview protection on,notesays who can open them. - After
rollback_deploymentthe app's production is held (production_held, "Production held" in the console): new production builds are built but not served on the production address.promote_deploymentwith a finished production deployment serves it without a rebuild and lifts the hold; with the one serving now it only lifts the hold.list_deploymentslists held apps inproduction_held. - With
wait(seconds, up to 120) they wait for the build to finish (readyorerror) and answer with the result. A failed build comes witherrorand the end ofbuild_log; one not finished in time comes withstill_running: trueandretry_after_seconds, after whichget_deploymentwithwaitwaits on.waitoncreate_projectwaits for the database, andstatusinlist_projectsisready,provisioning,failedorpaused. advisorsin the answer is the number of critical security problemsget_advisorsfinds (a rule that lets anyone write, a view that skips the rules) and the top 3. By default they are reported and the deploy goes ahead. Withblock_on_advisors: truea production deploy is refused while there are any (previews are not held back);oneend deploy --block-on-advisorsdoes the same. Deploys started by a git push are not held back.