---
title: "Resources"
description: "The Cloudflare resources each Runtime Context runs on, what creates them, and how to see and delete them."
canonical_url: "https://nuxtstart.com/docs/deployment/resources"
---

Every Cloudflare resource your project runs on is named `<slug>-<app>-<context>`, and the first run
that deploys a context creates it. There's no provisioning step to run: every run that deploys,
pull requests included, finds its context's resources by name and creates the one that's missing.

## What each context gets

`<context>` is the Runtime Context as it is — `development`, `preview`, `staging` or `production`.

<table>
<thead>
  <tr>
    <th>
      Resource
    </th>
    
    <th>
      For
    </th>
    
    <th>
      Holds
    </th>
    
    <th>
      Name
    </th>
    
    <th>
      Created by
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Worker
    </td>
    
    <td>
      each app
    </td>
    
    <td>
      the code, one version per deploy
    </td>
    
    <td>
      <code>
        <slug>-<app>-<context>
      </code>
    </td>
    
    <td>
      the deploy
    </td>
  </tr>
  
  <tr>
    <td>
      R2 bucket
    </td>
    
    <td>
      <code>
        apps/web
      </code>
    </td>
    
    <td>
      uploaded files
    </td>
    
    <td>
      <code>
        <slug>-web-<context>
      </code>
    </td>
    
    <td>
      the resources step
    </td>
  </tr>
  
  <tr>
    <td>
      Hyperdrive configuration
    </td>
    
    <td>
      <code>
        apps/web
      </code>
    </td>
    
    <td>
      the pooled connection to Postgres
    </td>
    
    <td>
      <code>
        <slug>-web-<context>
      </code>
    </td>
    
    <td>
      the resources step
    </td>
  </tr>
  
  <tr>
    <td>
      D1 database
    </td>
    
    <td>
      <code>
        apps/site
      </code>
    </td>
    
    <td>
      the <code>
        @nuxt/content
      </code>
      
       dump
    </td>
    
    <td>
      <code>
        <slug>-site-<context>
      </code>
    </td>
    
    <td>
      the resources step
    </td>
  </tr>
  
  <tr>
    <td>
      Postgres
    </td>
    
    <td>
      <code>
        apps/web
      </code>
    </td>
    
    <td>
      application data
    </td>
    
    <td>
      yours to choose
    </td>
    
    <td>
      you, at your provider
    </td>
  </tr>
</tbody>
</table>

`preview`'s Worker serves no deployment of its own. The first pull request's run creates it, and
every pull request is a Preview on it, bound to preview's own bucket and content database. Its
`apps/web` Preview binds a Preview Database instead of preview's pool.
[Pull request previews](/docs/deployment/pipeline#pull-request-previews) has the rest.

The slug is `PROJECT_SLUG` in `.env.project.schema`, and each application's `.env.schema` builds the
names from it, so no value file holds one. [Project identity](/docs/reference/project-identity) is the
full rule. Postgres is the one resource you create yourself, one per deployed context, at the
Getting Started stage that adds the context.

## How a run creates and finds them

`Upsert the Cloudflare resources` in `.github/workflows/deploy.yml` is the resources step. It runs
before the build in every run that deploys, previews included:

1. It reads each resource name through varlock.
2. It finds each resource by that name, and creates the one that's missing.
3. It updates `apps/web`'s Hyperdrive configuration from `DATABASE_URL`. On a pull request, it
creates or reuses that pull request's Preview Database and its own configuration instead.
4. It hands the D1 and Hyperdrive ids to the build.

`varlock-wrangler deploy` and `varlock-wrangler preview` only bind what the step found, so a
context's first run creates its resources and every later run finds them.

D1 is bound by id as well as by name, because Cloudflare refuses a D1 binding without an id in a
Preview. That id is `CLOUDFLARE_D1_DATABASE_ID`, and the step is its only source: no value file
holds it.

A new resource takes a name item in the application's `.env.schema`, its binding, and one
find-or-create line in the step, in the shape of the ones already there. A new resource type also
needs [its token permission](#the-token-each-resource-type-needs).

### The Hyperdrive configuration

A Hyperdrive configuration is built from the database's credentials, so the step does more for it
than find it. It looks the configuration up by name through Cloudflare's API, updates it from
`DATABASE_URL` when it exists, and creates it when it doesn't.

No id is copied into a file, and rotating `DATABASE_URL` in the secret store reaches Hyperdrive on
that context's next run. A second configuration with the same name — one made by hand, say — stops
the step rather than letting it pick one.

Wrangler reads the host, port, user, password and database name out of `DATABASE_URL`, and
percent-decodes them. Query parameters such as `sslmode` and `channel_binding` don't reach Hyperdrive,
so paste the string your provider gives you unchanged: the migration step connects with all of it.

## `local`

`local` never deploys, so nothing creates a `-local` resource, and today it needs none. Uploads land in
`.data/blob`, the database is the Docker Postgres from
[Local setup](/docs/getting-started/local-setup), and the site reads its content locally.

The names still resolve — `<slug>-web-local`, `<slug>-site-local`. When a feature needs a resource
that exists only on Cloudflare, AI Search for example, create it once under that name with
`wrangler <resource> create`, and every developer on the project shares it.

The one exception is a stray Worker. `<slug>-<app>-local` exists only if someone deployed by hand
without setting `APP_RUNTIME_CONTEXT` —
[Environment configuration](/docs/getting-started/technical-details#environment-configuration) says
how that happens. Nothing uses it, so [delete it](#delete-a-resource).

## See what exists

In the dashboard, go to **Workers & Pages**, select a Worker, and open **Bindings**. It names the
bucket, database and pool that Worker's version is bound to. For a pull request's bindings, pick its
Preview from the preview Worker's **Preview** selector first. From a terminal, signed in with
`pnpm exec wrangler login`:

```bash
pnpm exec wrangler r2 bucket list
pnpm exec wrangler d1 list
pnpm exec wrangler hyperdrive list
```

Each lists every resource of its type in the account, so look for your slug when the account holds
more than one project.

## Delete a resource

Nothing deletes a resource automatically. Removing a binding, an application or a Runtime Context
leaves its resources in place, data included. Delete them by hand once nothing needs them:

<table>
<thead>
  <tr>
    <th>
      Resource
    </th>
    
    <th>
      Command
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      R2 bucket
    </td>
    
    <td>
      <code>
        pnpm exec wrangler r2 bucket delete <slug>-web-<context>
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      D1 database
    </td>
    
    <td>
      <code>
        pnpm exec wrangler d1 delete <slug>-site-<context>
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Hyperdrive configuration
    </td>
    
    <td>
      <code>
        pnpm exec wrangler hyperdrive delete <id>
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Worker
    </td>
    
    <td>
      <code>
        pnpm exec wrangler delete <slug>-<app>-<context>
      </code>
    </td>
  </tr>
</tbody>
</table>

A Hyperdrive configuration is deleted by id, which `wrangler hyperdrive list` prints. Cloudflare
refuses to delete a bucket that still holds objects, so empty it first. Postgres is yours to delete at
your provider.

Delete a context's resources only once nothing deploys that context. A resource deleted while
something still deploys it comes back, empty, on the next run.

A pull request's Preview and its Preview Database aren't resources in this sense. Closing the pull
request deletes them —
[Pull request previews](/docs/deployment/pipeline#pull-request-previews) covers their lifetime.

### Renaming your project

Changing `PROJECT_SLUG` changes every name, so the next deploy into each context creates new, empty
resources and new Workers beside the old ones. The old ones keep their data until you delete them.
Move what you need first, and rewrite the origins in your value files, because an origin carries the
Worker name.

## The token each resource type needs

The deploy authenticates with one Cloudflare token, and that token needs an **Edit** permission for
every resource type the resources step creates.
[The Cloudflare API token](/docs/getting-started/deploying-development#the-cloudflare-api-token)
lists them.
A new resource type needs its permission added to the token first; a run without it fails at the
resources step with Cloudflare's authentication error.

## Going further

- [Deploy pipeline](/docs/deployment/pipeline) — which event deploys which context, and what each
application binds
- [Deploying development](/docs/getting-started/deploying-development) — the repository's
one-time Cloudflare setup, and the first push to `development`
- [Adding pull request previews](/docs/getting-started/adding-pull-request-previews) — the first
pull request, which creates preview's Worker and resources
- [Adding staging](/docs/getting-started/adding-staging) — the optional `staging` context, whose
first push creates its resources
- [Going to production](/docs/getting-started/going-to-production) — the first push to `main`, which
creates production's resources

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
