tuqo

Deploy from GitHub Actions and GitLab CI in one step

If your CI already builds the site, you do not need a separate hosting pipeline. One line after npm run build is enough:

npx @tuqo/cli deploy ./dist --site $TUQO_SITE_ID --wait

The key lives in the TUQO_API_KEY secret and the site ID in a variable. The CLI does the rest: it computes the sha256 of every file, asks the server which blobs it does not have yet, uploads only the missing ones and publishes the new version. A repeat deploy of the same site is almost instant: editing text does not push the photos again.

Step 1. A key with editor rights

Panel → project → API keys → create a key. The editor level is enough to deploy (readonly cannot publish, and full is only needed to manage the project). The full key, tqk_<prefix>_<secret>, is shown once, so copy it right away. After that you can only reissue it.

The site ID (site_id) is shown on the site’s page in the panel; whoami and create_site in the API return it too.

Step 2. Secrets in the repository

GitHub: Settings → Secrets and variables → Actions → New repository secret → TUQO_API_KEY. The site ID does not need to be secret: add it on the Variables tab as TUQO_SITE_ID.

GitLab: Settings → CI/CD → Variables → Add variable. Mark the key Masked, so it never shows up in job logs, and Protected, so only pipelines on protected branches such as main can read it (merge requests from forks cannot).

Never keep the key in the repository. If you use a multi-site tuqo.json, the CLI checks the file on purpose and refuses to run if it finds a key field there.

Step 3. GitHub Actions

name: Deploy to Tuqo
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci && npm run build
      - run: npx @tuqo/cli deploy ./dist --site ${{ vars.TUQO_SITE_ID }} --wait
        env:
          TUQO_API_KEY: ${{ secrets.TUQO_API_KEY }}

Step 3 (alternative). GitLab CI

deploy:
  image: node:20
  stage: deploy
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  script:
    - npm ci && npm run build
    - npx @tuqo/cli deploy ./dist --site "$TUQO_SITE_ID" --wait
  # TUQO_API_KEY and TUQO_SITE_ID: Settings → CI/CD → Variables (the key is masked)

The --wait flag waits until the version is published and prints the live URL on the second line. On failure it exits with code 1, so the CI job turns red instead of passing “green” with an unpublished version. Logs and progress go to stderr, which means you can safely capture stdout in a variable:

URL=$(npx @tuqo/cli deploy ./dist --site "$TUQO_SITE_ID" --wait | tail -n1)
echo "Published: $URL"

Pull request previews: —no-activate

The --no-activate flag builds a version but does not put it on the live address: visitors keep seeing the current one. The build gets a secret link, which is handy to post as a comment on the PR:

name: Preview
on: pull_request
jobs:
  preview:
    runs-on: ubuntu-latest
    env:
      TUQO_API_KEY: ${{ secrets.TUQO_API_KEY }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci && npm run build
      - id: dep
        run: |
          D=$(npx @tuqo/cli deploy ./dist --site ${{ vars.TUQO_SITE_ID }} --no-activate)
          echo "url=$(npx @tuqo/cli preview "$D")" >> "$GITHUB_OUTPUT"
      - run: echo "Preview: ${{ steps.dep.outputs.url }}"

Without --wait, stdout holds just the deploy ID, which is what preview takes. The preview command is idempotent: calling it again returns the same link. Happy with the result? Publish it with npx @tuqo/cli promote <deploy_id>; the same command rolls the site back to any kept version.

The preview link does not ask for a password, even if the site is gated, so share it only with people you trust; you can turn it off in the panel. Build preview is available from the Start plan (590 ₽/mo; approximate prices in dollars and euros are on the pricing page). Details are on the build preview page.

How this differs from Git CD

The CLI in your CIGit CD
Who buildsyour runner, your stepsTuqo: Node 20, npm ci && npm run build
What to set upYAML + a secret with the keylink the repository in the panel
Plan build minutesnot usedused by every build
Tests, linters, code generationanything you likeno, the standard build only
Webhooknot neededcreated automatically

The rule is simple. You need your own steps before the build: use the CLI from CI. You just want “push → site in production”: use Git CD, which needs no YAML and no keys. More in the guides on auto-deploy from Git and CI/CD without GitHub Actions.

FAQ

Do I need to install the CLI in the image?

No. npx @tuqo/cli downloads the package on first run. It needs Node.js 18 or newer, and the package has no dependencies. On GitLab the node:20 image is enough.

What are the limits of a single deploy?

Up to 2000 files and up to 50 MB per file, in total within your plan’s storage quota. The folder must have index.html at its root. Files go up one by one, so there is no request body size limit.

Can I publish several sites from one repository?

Yes. Put a tuqo.json with a folder-to-site map at the repository root and run npx @tuqo/cli deploy without arguments: one run publishes every site and prints one line per site to stdout. Pass the key in the environment variable as before.

{ "sites": { "site/com": "<site_id_com>", "site/ru": "<site_id_ru>" } }

The build failed in CI. What happens to the site?

Nothing changes: until a new version is published, the live address serves the previous one. With --wait, a failed deploy ends the command with code 1, so the pipeline stops on its own.

All CLI commands and flags → · Build preview → · Auto-deploy from Git →