# Managing Flights as code
> Version Flight source in Git, deploy with a service account, and use MotherDuck Blueprints for pull request previews and production deployments.
Keep your Flight's Python source, dependencies, and settings in Git so your team can review changes and deploy them with a shared service-account identity. Use [MotherDuck Blueprints](https://github.com/motherduckdb/motherduck-blueprints) for automated previews and production deployments, or the [MotherDuck CLI](/sql-reference/motherduck-cli/flight/) to pull and push individual Flights.

## Before you start

- [Create a service account](/key-tasks/service-accounts-guide/create-and-configure-service-accounts/) and a read/write token for deployment. Grant the account the database privileges your Flight needs.
- Choose that account before the first deployment. A Flight belongs to the account that creates it; your CI service account can't update a Flight created by your personal account.
- Create any [Flight secrets](/key-tasks/flights/flights-authentication-config-and-secrets/#secrets-sensitive-environment-variables) while connected as the service account. Store secret names, not values, in Git.

The deployment token authenticates the CLI or CI job as the service account. A Flight's optional `access_token_name` selects a runtime token **belonging to that same account**; it doesn't change the Flight's owner. Omit it when creating a Flight to use the service account's default `MotherDuck Flights` token. See [service accounts for production Flights](/key-tasks/flights/flights-authentication-config-and-secrets/#service-accounts-for-production-flights).

## Blueprints: deploy previews and production

Blueprints manages Flight source and settings alongside the shares and Dives that depend on its data. Its template includes GitHub Actions for deployment and preview cleanup.

### 1. Create a repository and configure credentials

Create a private repository from the [Blueprints template](https://github.com/motherduckdb/blueprints-template/generate). You need repository admin access and a GitHub plan that supports Environments for private repositories.

In **Settings → Environments**, create `motherduck-production` and add the service-account token as an environment secret named `MOTHERDUCK_TOKEN`. Don't commit the token or put it in a package's config.

The default template uses this identity for previews and production. For separate credentials and release-based production deployment, follow [add staging](https://github.com/motherduckdb/motherduck-blueprints/blob/main/docs/setup-your-repository.md#add-staging-optional).

### 2. Keep source and settings together

The template includes a working pipeline under `flights/wikipedia-pageviews-ingest/`:

```text
flights/
  wikipedia-pageviews-ingest/
    blueprint.yml
    src/
      flight.py
      requirements.txt
```

Edit the Python in `src/flight.py`, pin dependencies in `src/requirements.txt`, and keep deployment settings in `blueprint.yml`. The Flight declaration includes:

```yaml
resources:
  flights:
    pageviews_loader:
      name: wikipedia-pageviews
      source: src/flight.py
      requirements: src/requirements.txt
      scheduleCron: 17 6 * * *
      runOnDeploy: true
      waitForRun: success
      secrets: []
```

This is an excerpt, not a complete manifest. Keep the template's supporting share, config, and preview overrides. `runOnDeploy: true` runs the Flight during deployment, and `waitForRun: success` waits for it to succeed before deploying consumers. Preview schedules are disabled; the example runs daily in production.

For your own workload, adapt the example or use `make new-project revenue` to scaffold a Flight and Dive together. Follow the [Blueprints manifest reference](https://github.com/motherduckdb/motherduck-blueprints/blob/main/docs/blueprint-yml-reference.md#flights) for fields such as `accessTokenName`, `secrets`, and target-specific config. These manifest field names differ from the CLI's `flight.metadata.json` fields.

### 3. Review a preview and deploy production

1. Change the example Flight package on a feature branch and open a pull request against `main`.
2. Wait for **Deploy Blueprints** to finish. Inspect the plan in the Actions summary, open the preview Dive from the PR comment, and verify the data the Flight produced.
3. Merge the PR. With the default setup, the workflow deploys the changed packages to production. Closing the PR cleans up its preview resources.

Before deploying your own pipeline, check that its preview config writes to preview databases and shares, not hard-coded production destinations. Turning off a schedule doesn't prevent `runOnDeploy` from writing data or calling external services. Fork PRs validate without deployment credentials.

See [Blueprints setup and troubleshooting](https://github.com/motherduckdb/motherduck-blueprints/blob/main/docs/setup-your-repository.md) for approval rules, validation, and cleanup. Removing package files doesn't delete deployed production resources.

## Pull and push an individual Flight with the CLI

Use this route for local editing or an existing CI pipeline that doesn't need Blueprints dependency management. Install the [MotherDuck CLI](/getting-started/interfaces/motherduck-cli/install/) first.

### 1. Connect as the intended owner

Supply the service-account token through your secret manager as `MOTHERDUCK_TOKEN`, then check the active credential:

```bash
motherduck status
motherduck flight guide
```

`MOTHERDUCK_TOKEN` takes precedence over a saved personal sign-in. Read the authoring guide before changing the Flight.

### 2. Pull an existing Flight or initialize one

Pull into a fresh directory: `pull` overwrites local source and metadata.

```bash
motherduck flight list --output json
motherduck flight pull <flight_id> --dir flights/daily-load
```

Or initialize a local Flight:

```bash
motherduck flight init flights/daily-load --name daily-load
```

Edit and commit `main.py`, `requirements.txt`, and `flight.metadata.json`. Pin a [MotherDuck-supported DuckDB version](/key-tasks/flights/packages-and-runtime/) in the requirements if your code connects to MotherDuck.

### 3. Push, verify, and retain the ID

```bash
motherduck flight push flights/daily-load
motherduck flight run flights/daily-load
motherduck flight list-runs flights/daily-load --output json
motherduck flight logs flights/daily-load --run <run_number>
```

A push creates a Flight when the metadata has no `id` and updates that ID afterward. Commit the metadata after the first push so subsequent checkouts update the same Flight instead of creating duplicates. Keep separate IDs for separate deployment targets. A successful push doesn't prove the Flight ran successfully: check the run's terminal status, logs, and output tables before enabling its schedule.

In CI, inject the same owner's `MOTHERDUCK_TOKEN`, install the CLI, and run `motherduck flight push` against the checked-in directory. Don't deploy the same Flight through both Blueprints and an independent push workflow; choose one deployment workflow for each Flight.

## Adopt a Flight created under your personal account

Importing source doesn't transfer ownership. To keep an existing Flight's ID, deploy with its owner's credentials. To move to service-account ownership:

1. Export the source and settings using your personal identity.
2. Connect as the service account and recreate the required secrets and Flight with a separate ID. With the CLI, initialize a fresh directory and copy the source and settings without the personal Flight's `id`.
3. Run and verify the replacement, then disable the old schedule before enabling the replacement's schedule. Update any Dive or automation that references the old Flight ID.

For Blueprints, follow [adopt existing resources](https://github.com/motherduckdb/motherduck-blueprints/blob/main/docs/adopt-existing-resources.md). Imported packages start with deployment disabled so you can review ownership, settings, and dependencies before activating them. Importing alone doesn't move secrets or data.

## Related resources

- [Managing Dives as code](/key-tasks/dives/managing-dives-as-code/)
- [Flight authentication, config, and secrets](/key-tasks/flights/flights-authentication-config-and-secrets/)
- [Scheduling and runs](/key-tasks/flights/scheduling-and-runs/)
- [`motherduck flight` reference](/sql-reference/motherduck-cli/flight/)


---

## Docs feedback

MotherDuck accepts optional user-submitted feedback about this page at `GET https://motherduck.com/docs/api/feedback/agent`.
For agents and automated tools, feedback submission should be user-confirmed before sending.

URL-encode query parameter values and send a GET request:

```text
GET https://motherduck.com/docs/api/feedback/agent?page_path=%2Fkey-tasks%2Fflights%2Fmanaging-flights-as-code%2F&page_title=Managing%20Flights%20as%20code&text=<url-encoded user feedback, max 2000 characters>
```

Optionally append `&source=<url-encoded interface identifier>` such as `claude.ai` or `chatgpt`.

`page_path` and `text` are required; `page_title` and `source` are optional. Responses: `200 {"feedback_id": "<uuid>"}`, `400` for malformed query parameters, and `429` when rate-limited.
