Deploy Nuxt on the Edge

Learn how to host your full-stack Nuxt application globally with minimal configuration.
To deploy your Nuxt application on the Edge, we use Cloudflare Pages. Therefore, we require you to create a Cloudflare account. You can deploy NuxtHub projects with a free Cloudflare account.

The NuxtHub Admin is made to simplify your experience with NuxtHub, enabling you to effortlessly manage teams and projects, as well as deploying NuxtHub application with zero-configuration on your Cloudflare account.

NuxtHub Admin Deployments

Production vs Preview Deployments

NuxtHub supports two types of deployments: production and preview.

Production Deployments

  • When setting up your project, you can specify a production branch (defaults to main)
  • Successful deployments to the production branch will be:
    • Accessible via your primary domain
    • Also available at <commit>.<project>.pages.dev

Preview Deployments

  • Any deployment from a non-production branch (including pull requests) is considered a preview
  • Successful preview deployments are accessible via:
    • <commit>.<project>.pages.dev
    • <branch>.<project>.pages.dev
Toggle between production and preview environments in the NuxtHub admin using the "Preview mode" switch.

NuxtHub CLI

Deploy your local project with a single command:

Terminal
npx nuxthub deploy

The command will:

  1. Ensure you are logged in on admin.hub.nuxt.com
  2. Make sure you linked your Cloudflare account
  3. Link your local project with a NuxtHub project or help you create a new one
  4. Build your Nuxt project with the correct preset
  5. Deploy it to your Cloudflare account with all the necessary resources (D1, KV, R2, etc.)
  6. Provide you with a URL to access your project with a free <my-app>.nuxt.dev domain
You can also install the NuxtHub CLI globally with: npm i -g nuxthub.

Usage with CI/CD

If you are using GitHub for your project, jump to the Github Action section.
The nuxthub deploy command is designed to run non-interactively in CI/CD environments. It won’t prompt for additional input (such as logging in or linking the project). As long as the required environment variables are set, deployment will proceed automatically.

To integrate the nuxthub deploy command within your CI/CD pipeline, set the following environment variables:

  • NUXT_HUB_PROJECT_KEY – Your project key available in:
    • Your project settings in the NuxtHub Admin
    • Your .env file (if you ran npx nuxthub link)
  • NUXT_HUB_USER_TOKEN – Your personal token, available in User settingsTokens in the NuxtHub Admin

Example command:

Terminal
NUXT_HUB_PROJECT_KEY=<my-project-key> NUXT_HUB_USER_TOKEN=<my-user-token> npx nuxthub deploy

This will authenticate your user and link your NuxtHub project for deployment.

For security, do not hardcode these values. Instead, store them as environment variables in your CI/CD pipeline.

GitHub Action

After linking a GitHub repository to your project, NuxtHub automatically adds a GitHub Actions workflow to automatically deploy your application on every commit using the NuxtHub GitHub Action.

NuxtHub integrates with GitHub deployments. This allows you to:

After deploying from a pull request, NuxtHub automatically adds a comment with information about the deployment.

NuxtHUb GitHub Action commenting on pull requests
You can customise the workflow to tailor to any specific custom DevOps requirements.
Projects created prior to releasing our GitHub Action uses Pages CI for deployments. Read our migration guide.

Default workflow

The GitHub Workflow added to your repository is automatically tailored to your project's package manager. This is an example of a workflow added for a project using pnpm.

We support pnpm, yarn, npm and Corepack. If you use a different package manager, you can customise the generated nuxthub.yml GitHub Action.

.github/workflows/nuxthub.yml
name: Deploy to NuxtHub
on: push

jobs:
  deploy:
    name: "Deploy to NuxtHub"
    runs-on: ubuntu-latest
    environment:
      name: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
      url: ${{ steps.deploy.outputs.deployment-url }}
    permissions:
      contents: read
      id-token: write

    steps:
      - uses: actions/checkout@v4

      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 9

      - name: Install Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install

      - name: Build application
        run: pnpm run build

      - name: Deploy to NuxtHub
        uses: nuxt-hub/action@v1
        id: deploy

Options

Inputs

The following input parameters can be provided to the GitHub Action. Learn more about Workflow syntax for GitHub Actions on GitHub's documentation.

directory
string

The directory of the built Nuxt application. Defaults to dist.

project-key
string

The project key of the NuxtHub project to deploy to. If the repository is linked to more than one project, project key is required.

Outputs

The GitHub Action provides the following outputs that you can use in subsequent workflow steps.

environment
'production' | 'preview'

The environment of the deployment (e.g. production, preview).

deployment-url
string

The URL of the deployment. For preview environments, it links to the deployment of the commit.

Examples:

branch-url
string

The permanent URL for the current branch deployment.

Examples:

Environment Variables & Secrets

NuxtHub automatically copies all your project's environment variables to your GitHub repository actions environment variables.

When encrypting an environment variable in the NuxtHub Admin, a GitHub actions secret will be created in your repository.

You can view the environment variables and secrets synchronized by NuxtHub by navigating to Repository Settings -> Secrets and variables -> Actions on GitHub.

If you have a private repository on a free GitHub account or organization, NuxtHub won't be able to sync the env variables & secrets as GitHub repository environments (production / preview) are not available. In this case, you must manually set up the environment variables by navigating to Repository Settings -> Secrets and variables -> Actions on GitHub.

In order to use GitHub Actions variables and secrets, you need to update your workflow to expose them as environment variables:

.github/workflows/nuxthub.yml
  - name: Build application
    run: pnpm run build
+   env:
+     NUXT_PUBLIC_VAR: ${{ vars.NUXT_PUBLIC_VAR }}
+     NUXT_UI_PRO_LICENSE: ${{ secrets.NUXT_UI_PRO_LICENSE }}
This is mostly useful for build-time environment variables.

Setup

Creating a new project

When creating a new project from a template, or importing a Git repository, the GitHub Action workflow will automatically be set up for you.

Linking a repository to existing projects

Link your project to a GitHub repository within NuxtHub Admin → Projects → <Your Project> → Settings → General → Git Repository

Migration from Cloudflare CI to GitHub Actions

Migrate your project to GitHub Actions within NuxtHub Admin → Projects → <Your Project> → Settings → General → Git Repository → Begin Migration.

Only non-secret environment variables are automatically copied to GitHub. Existing environment secrets are not automatically migrated to GitHub, and should be updated to sync them to GitHub.

Monorepo setup

Our GitHub integration supports deploying multiple applications from the same repository.

When linking a Git repository, set "project root directory" to the base folder of your Nuxt application corresponding to that NuxtHub project.

When a repository is already linked to at least one project, additional projects linked will have the generated GitHub Actions workflow named nuxthub-<projectSlug>.yml.

When multiple projects are linked to the same repository, the project-key input parameter must be specified on each Deploy to NuxtHub GitHub Action.

Current limitations

  • Separate applications should be deployed using different workflow jobs.

GitLab CI

This section will guide you to implement the GitLab CI. The integration with GitLab CI builds on the Usage with CI/CD section, make sure you have those two variables NUXT_HUB_PROJECT_KEY and NUXT_HUB_USER_TOKEN.

User Token Variable

It is good practice to place the user token inside GitLab CI Variables.
  1. Open your Repository (on GitLab) > Settings > CI/CD > Variables
  2. Click on Add variable
  3. Set Visibility to Masked and hidden
  4. Remove protected Flag (since we may use this variable also on non-protected branches)
  5. Give a Key name = NUXT_HUB_USER_TOKEN
  6. Paste your NUXT_HUB_USER_TOKEN — Your personal token, available in User settingsTokens in the NuxtHub Admin
  7. Click Add variable
The NUXT_HUB_PROJECT_KEY is used later in Configure Projects for GitLab.

Project Configuration

  1. Create a .gitlab-ci.yml in your repository root
  2. Paste the following configuration
.gitlab-ci.yml
# if one job fails, pipeline should fail
workflow:
  auto_cancel:
    on_job_failure: all
    
variables: 
  APP_PATH: "PATH/TO/YOUR/APP"
  NUXT_HUB_PROJECT_KEY: "YOUR_NUXT_HUB_PROJECT_KEY"

# add additional steps as needed
stages:
  - deploy
  - callback

deploy_project:
  stage: deploy
  # here we use Bun, you can change this.
  image: "oven/bun:slim"
  script:
    - echo "Deploying project_a app..."
    - cd $APP_PATH
    # you can not use node_modules from cache, since nuxthub needs write access
    - bun install
    # if you set up your variables correctly this should deploy successfully
    - bunx nuxthub deploy 
  rules:
    # here we configure auto deploy on branch: staging and main
    - if: '$CI_COMMIT_BRANCH == "staging" || $CI_COMMIT_BRANCH == "main"'
      
manual_deploy_project:
  stage: deploy
  image: "oven/bun:slim"
  when: manual
  script:
    - echo "Deploying project_a app..."
    - cd $APP_PATH
    - bun install
    - bunx nuxthub deploy

callback:
  stage: callback
  script:
    - echo "Deploy reached."
If you have a monorepo with multiple projects (apps), do this step for each of your project (e.g. ./apps/project-foo/.gitlab-ci.yml). Then follow the Monorepo Setup section.
The callback job is needed to mark the pipeline as successfully, especially if deploy_project has not run.
You can avoid this by setting allow-failure: true but this will result in other drawbacks. Or simply deploy on every branch, which results in more traffic.
You can always deploy from your working branches, just use the manual trigger. Deployed branches different from 'main' (or what you configured in nuxthub dashboard as your main) will be marked as preview.

Monorepo Setup

If you have a monorepo with multiple apps (e.g. ./apps/project-foo), then we make sure our pipelines can run parallel.

  1. Create in your repository root a .gitlab-ci.yml
  2. Paste the following configuration
.gitlab-ci.yml
# if one job fails, pipeline should fail
workflow:
  auto_cancel:
    on_job_failure: all
stages:
  - trigger_apps

trigger_project_a:
  stage: trigger_apps
  rules:
    - changes:
        - "apps/project-foo/**/*"
  trigger:
    strategy: depend
    include:
      - local: "apps/project-foo/.gitlab-ci.yml"

trigger_project_b:
  stage: trigger_apps
  rules:
    - changes:
        - "apps/project-bar/**/*"
  trigger:
    strategy: depend
    include:
      - local: "apps/project-bar/.gitlab-ci.yml"
  
add_manual_triggers:
  stage: trigger_apps
  trigger:
    strategy: depend
    include:
      - local: ".manual-triggers.yml"
Change the paths to your own project paths.

This configuration separates your main pipeline from child pipelines, each project (app) has its own .gitlab-ci.yml Those child pipelines are only triggered if changes are made in their app folder.

Sometimes GitLab changes are not recognized (previous pipeline failed and new push has no changes in app folder), for that case, you can add manual triggers for the child pipelines by adding a .manual-triggers.yml in the project root.

.manual-triggers.yml
workflow:
  auto_cancel:
    on_job_failure: all

stages:
  - trigger_apps
  - callback

trigger_project_a:
  stage: trigger_apps
  when: manual
  trigger:
    strategy: depend
    include:
      - local: "apps/project-foo/.gitlab-ci.yml"

trigger_project_b:
  stage: trigger_apps
  when: manual
  trigger:
    strategy: depend
    include:
      - local: "apps/project-bar/.gitlab-ci.yml"
          
callback:
  stage: callback
  script:
    - echo "manual triggers set"
With the options depends and workflow.auto_cancel.on_job_failure: all a pipeline is failed, if one job fails. This assures a clean main / staging branch. Change it to your needs.

Cloudflare Pages CI

Importing an existing Cloudflare Pages project that is already linked to a Git repository will use Cloudflare Pages CI to deploy your project.

  • Each commit will trigger a new deployment within Pages CI.
  • Environment variables set within NuxtHub Admin will be available during CI.
All existing projects with a Git repository linked to Cloudflare Pages prior to our GitHub Action being released uses Cloudflare Pages CI for automated deployments.
You can migrate from Cloudflare Pages CI to GitHub Actions at any time. Read our migration guide.

Self-hosted

You can deploy your project on your own Cloudflare account without using the NuxtHub Admin.

For that, you need to create the necessary resources in your Cloudflare account and configure your project to use them (D1, KV, R2, etc.).

You only need to create these resources if you have explicitly enabled them in the Hub Config.

Then, create a Cloudflare Pages project and link your GitHub or GitLab repository and choose the Nuxt Framework preset in the build settings.

Once your project is created, open the Settings tab and set:

  • Runtime > Compatibility flags
    • Add the nodejs_compat flag
  • Bindings
    • KV namespace: KV and select your KV namespace created
    • KV namespace: CACHE and select your KV namespace for caching created
    • R2 bucket: BLOB and select your R2 bucket created
    • D1 database: DB and select your D1 database created
    • AI: AI
    • Browser: BROWSER
    • Vectorize: VECTORIZE_<index name in upper case> and select your Vectorize index created
      # Create the Vectorize index manually using
      npx wrangler vectorize create <index-name> --dimensions=<dimensions> --metric=<metric>
      

Go back to the Deployment tab and retry the last deployment by clicking on ... then Retry deployment.

Once the deployment is done, you should be able to use npx nuxt dev --remote after configuring the remote storage