Export your source to GitHub

Initialize an empty GitHub repository with the source Volcano stores for your project, then deploy it from Git.

Export creates the first commit in an empty GitHub repository. It pushes the complete project directly to the configured production branch, which triggers the normal Git deployment flow.

curl -X POST "https://api.volcano.dev/projects/$PROJECT_ID/source-export" \
  -H "Authorization: Bearer $VOLCANO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"production_branch":"main","repo_id":873345021}'
{
  "repo_full_name": "acme/storefront",
  "branch": "main",
  "commit_sha": "6f2b1c9a4e8d3f7b0a5c2e9d1f4b8a6c3e7d0b25",
  "file_count": 12,
  "skipped": [],
  "omitted": [{ "kind": "migrations", "resource": "", "path": "volcano/migrations" }]
}

Prepare the repository

  1. Create a GitHub repository without a README, license, .gitignore, or any other initial commit.

  2. Connect it to the project and export from the CLI. An empty repository has no default branch, so name the branch pushes will deploy from when you connect it:

    volcano git connect https://github.com/acme/storefront --production-branch main
    volcano git export

    volcano git export shows the repository and production branch and asks before it writes. In a script, pass the branch you expect and skip the prompt; the command refuses if the project's branch is different:

    volcano git export --branch main --yes --json

volcano git repos lists the repositories you can connect and marks the empty ones.

For API clients, connect the repository and configure Git auto-deploy first. Read repo_full_name, repo_id and production_branch from GET /projects/{id}/git-connection, show the repository and branch for confirmation, then send repo_id and production_branch to the export endpoint. If either changed in the meantime, export returns 409 without writing the repository. Read the connection again and ask the user to confirm what it holds now. repo_id is optional, but without it export writes to whatever repository is connected when the request arrives.

Export also returns 409 while a function or frontend deployment is queued or provisioning. Wait for that deployment to finish, then export again. It returns 409 too while a preview is serving any of the project's frontends, because the repository would not hold the source that frontend serves. Roll each such frontend back to its own build, then export again. Volcano checks both before creating or pushing the root commit.

Volcano does not create the repository. Export refuses any repository that already has a commit or branch. This avoids merges, conflict resolution, and overwriting existing history.

If your repository already contains the project, do not export. Push the complete project to its configured production branch instead. Git auto-deploy will deploy it, but it does not disable direct platform deploys. Source ownership changes only through the one-time export flow.

What export writes

The root commit uses the layout Git auto-deploy discovers:

volcano/
├── .gitignore
└── functions/
    ├── hello.js
    └── checkout/
        ├── index.js
        └── tax.js
volcano-config.yaml
package.json
frontends/
├── web/
│   └── package.json
└── admin/
    └── package.json
.volcano/
└── source-layout.json

Export supports multiple frontends and functions. Each frontend gets a frontends/<name>/ workspace, including its dependencies and original app root. Functions keep the existing single-file or directory layout.

The generated .volcano/source-layout.json records frontend names and app roots. Keep it in Git: it tells Volcano to deploy every exported frontend instead of using the single frontend in Git deploy settings. The Auto deploy and Deploy functions switches still apply.

The initial export and every later production-branch push deploy all configured resources, including those whose code has not changed. Git takes over source ownership only after a deployment covers every exported serving resource.

Export takes source from each function and frontend's latest successful deployment. A resource that has never deployed successfully appears in skipped and is not written.

Both kinds of function are exported into the same volcano/functions/ directory. Durable functions are marked with kind: durable in volcano-config.yaml, which is how the first push from the exported repository recreates them as durable rather than standard.

Export refuses to push when a currently serving resource has no readable stored source or cannot be represented in the repository layout. This keeps the first Git deployment from waiting on source that the commit does not contain.

Stored .gitignore files are committed as ordinary files. Their patterns do not remove other stored files from the export commit.

The omitted list reports content Volcano cannot or should not publish:

KindWhy
migrationsVolcano does not retain the migration files.
variable_valuesSecret values are never committed. Configure them through Volcano.
ignored_secretCredential-shaped files such as .env are excluded.
dependency_cacheGenerated dependency directories such as node_modules are rebuilt.
unsupported_entrySymlinks and other unsupported archive entries are excluded.

Export fails and names the path when stored source contains a file that should never be committed, such as a private key or credential store.

How ownership changes

Export is a one-time transition:

  1. Volcano verifies the confirmed repository and production branch still match the project, pins the branch, and changes the project to git_exporting. Direct source deploys and Git connection changes are frozen.
  2. Volcano creates one root commit and pushes it to the production branch.
  3. GitHub's signed push event confirms that the root commit reached the production branch. That commit or a newer production push starts the ordinary Git deployment and changes the mode to git_pending.
  4. After a complete production deployment succeeds, the mode becomes git.

The project stays locked if the deployment fails, or if a function holds only TypeScript, which isn't deployed. Fix the repository and push the production branch again. The latest complete successful deployment finishes the transition; the exported root commit does not need to deploy if a newer push supersedes it.

The pinned branch does not follow later GitHub default-branch changes. This keeps a repository rename from moving production during or after handover. After handover you can return it to the default with an empty production_branch.

To stop an incomplete transition and restore direct platform deploys, run volcano git export cancel, or call the API:

curl -X DELETE "https://api.volcano.dev/projects/$PROJECT_ID/source-export" \
  -H "Authorization: Bearer $VOLCANO_TOKEN"

Cancellation does not delete the repository or a commit that already reached it. If Volcano reserved the initial commit before cancellation, the one-time export remains consumed and cannot be run again. The confirmed production branch remains pinned. Once the repository has its first commit, send an empty production_branch to follow it again.

Check the state at any time. volcano git status reports it as the project's source of truth; the API returns it as mode:

curl "https://api.volcano.dev/projects/$PROJECT_ID/source-export" \
  -H "Authorization: Bearer $VOLCANO_TOKEN"
{
  "mode": "git_pending",
  "transition_started_at": "2026-08-25T09:14:02Z",
  "exported_at": "2026-08-25T09:14:04Z",
  "handed_over_at": null
}

After handover, push to the production branch to change or deploy source. Direct function and frontend deploys return 409. Variables, databases, storage, domains, and resource settings remain manageable through Volcano.

To deploy from another branch after handover, set it explicitly, then push it:

curl -X PUT "https://api.volcano.dev/projects/$PROJECT_ID/git-connection/production-branch" \
  -H "Authorization: Bearer $VOLCANO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"production_branch":"release"}'

Branch changes are refused while the project is git_exporting or git_pending so the initial push and deployment always use the branch the user confirmed.

Retry an uncertain push

If GitHub does not confirm whether the initial push succeeded, the endpoint returns a retryable error and the project remains git_exporting. Call the endpoint again, or rerun volcano git export. Volcano builds the same commit: it adopts that commit if it is already on the production branch, or retries the initial push while the repository is still empty.

If the commit reached GitHub but its push event never reaches Volcano, the project remains git_exporting. Cancel the transition with volcano git export cancel or DELETE /projects/{id}/source-export to restore platform deploys. The root commit stays in the repository and the one-time export remains consumed.

GuideDescription
Deploy from GitHubConnect a repository and deploy on every push
Configuration manifestvolcano-config.yaml reference

On this page