Guide 12 · Developer docs

Performance, caching, deployment and go-live

How Core dna caches pages, what makes a render fast, how code reaches a site and what stays behind, the go-live checklist, and running a site once it is live. For developers, leads and site operators who already build pages in a theme repository.

L2–L3
Unit 03 · The deployment model

What CI can do for a theme repo

Linting, checking that the committed build matches the source, keeping branches in sync and smoke-testing a deploy are worth automating. Proving the site renders correctly is not something CI can do for a theme, and it helps to know why.

Who this is for. Leads setting up a pipeline for a theme repository. Afterwards you can run a minimal pipeline that catches the common deploy failures, and explain to a client what it does not prove.

A theme repository has no application to start and no test suite to run: the templates render only inside the platform, against the site's database. That shapes what continuous integration can usefully do. It can check everything that is a property of the files, and it can check the deployed site from the outside. It cannot render a page from the repository on its own.

What it can do

  • Lint. Stylelint for the styles, ESLint for the scripts, on every pull request. Cheap, fast, and it ends style arguments in review.
  • Check the committed build. Run the production build and fail if the output differs from what is committed. This catches the most common deploy failure, and in CI nobody can skip it (Build before you push).
  • Enforce a bundle budget. Fail the build when an entry grows past its budget (a budget per page type).
  • Keep branches in sync. Merge master back into staging after every release and hotfix (automating the merge-back).
  • Smoke-test after a deploy. Request a fixed list of URLs on the environment just deployed and check each status and a piece of text that proves the right template rendered.

What it cannot do

  • Render a page from the repository. A template needs the platform's objects and the site's records. Compiling templates with stock Smarty or Twig catches some syntax errors, but not a method that does not exist on a record, a layout area name that is wrong, a call the site's security policy refuses, or a layout that points at a moved file.
  • See the database. Layouts, jobs, forms and settings are records, not files. CI cannot tell you that a template a layout points at was renamed (Code deploys, content does not).
  • Prove the site is correct. A smoke test proves the pages answer and contain what they should; people still need to look at staging before a release.

A minimal useful pipeline

For Bitbucket Pipelines; other CI services take the same steps.

YAML bitbucket-pipelines.yml
image: node:20

pipelines:
  pull-requests:
    '**':
      - step:
          name: Lint and check the committed build
          caches: [node]
          script:
            - npm ci
            - npm run lint
            - npm run build
            - git diff --exit-code --stat -- dist/
  branches:
    staging:
      - step:
          name: Smoke-test staging after the deploy
          script:
            - sleep 120
            - ./scripts/smoke.sh https://staging.example.com
    master:
      - step:
          name: Sync staging with master
          script:
            - git config user.name "Bitbucket Pipelines"
            - git config user.email "pipelines@example.com"
            - git fetch origin
            - git checkout staging
            - git merge origin/master --strategy-option theirs
            - git push origin staging

The deploy itself is not a CI step: the push deploys the environment on its own, through the platform's queue, which is why the smoke test waits first. Two minutes is a guess; if the test runs too early it tests the previous deploy, so compare the release hash on the page with the commit being tested (seeing which commit is live). The smoke script reads a list of URLs, the status each must answer and a piece of text each must contain:

Shell scripts/smoke.sh
#!/bin/sh
# smoke.sh <base url>: every line of smoke.txt is "path|status|text the page must contain"
base="$1"; fail=0
while IFS='|' read -r path want expect; do
  out=$(curl -s -w '\n%{http_code}' "$base$path")
  code=$(printf '%s' "$out" | tail -n 1)
  if [ "$code" != "$want" ] || ! printf '%s' "$out" | grep -q "$expect"; then
    echo "FAIL $path (answered $code, wanted $want)"; fail=1
  fi
done < smoke.txt
exit $fail
HTML smoke.txt
/|200|Shop by category
/about|200|Our story
/blog|200|Latest articles
/products/coffee|200|Add to cart
/does-not-exist-smoke|404|Page not found

Keep the not-found line: an error page that answers 200 is the kind of mistake a smoke test should catch, and so is one that answers 404 with the platform's default page instead of yours. Run it against staging after every push; for production, the launch-day checks are the equivalent (Launch-day monitoring).

Go deeper

Was this page helpful?

Your answer goes to the docs team.