Skip to content

Static Site

A plain HTML and CSS website uploaded straight to AppMecca object storage and served from the AppMecca edge cache. No container, no Dockerfile, no web server to configure — the simplest possible frontend deployment on AppMecca.

Overview

Repository git@gitlab.com:appmecca-sample-apps/static-site.git
Tech Stack HTML / CSS
Services web (type: static)
Database None
Cache None (the edge cache fronts it by default)
URL Pattern https://static-site-web-{group}.{env}.appmecca.net

What This App Demonstrates

  • Deploying a site with no container at all — type: static
  • The static_site: block: build command, output directory, index document
  • Why a static app needs no Dockerfile, no web server config, and no health check

appmecca.yaml

This is the complete file. There is no containers: block, because nothing is built into an image:

app_name: Static Site

static_site:
  build_command: "mkdir -p dist && cp index.html style.css dist/"
  output_dir: dist
  spa_fallback: false
  index_document: index.html
  error_document: index.html

deploy:
  - name: web
    primary: true
    type: static

type: static tells AppMecca to run your build_command, then upload everything in output_dir to object storage and serve it through the edge cache. The "build" here is just a copy — there is nothing to compile.

A type: static service takes no container-shaped fields

Declaring port, replicas above 1, drives, command or health_check on a type: static service is a validation error, not a silent no-op. There is no container for any of them to apply to.

What you do NOT need

A static app needs no Dockerfile, no containers: block, no nginx or other web server, and no /health endpoint. There is no container to build, run, health-check, or hold a memory slot on a host. If you find yourself writing a web-server config file for a static site, something has gone wrong.

Step-by-Step Deployment

1. Register the app

mecca register git@gitlab.com:appmecca-sample-apps/static-site.git -e dev

2. Build and deploy

mecca app deploy static-site -e dev

The build runs your build_command in a clean environment, uploads output_dir to object storage under a per-commit prefix, and points the edge cache at it.

Expected output
Queued: 4f2a1c9e

3. Watch it land

mecca queue status 4f2a1c9e -e dev

Then open the site:

curl https://static-site-web-{group}.dev.appmecca.net

The first deploy is live immediately

A brand-new edge-cache distribution takes several minutes to reach every edge location. Rather than serving errors during that window, AppMecca serves your real content through its warm-up service and switches over once the distribution has propagated. Your URL works from the moment the deploy completes.

Key Concepts

build_command and output_dir

These are the only two settings most static apps need.

Field Default What it does
build_command npm run build Produces your bundle. Must exit 0 and populate output_dir.
output_dir dist The directory that gets uploaded.

Common output_dir values: dist (Vite, SvelteKit static), build (Create React App), out (Next.js export), public (Hugo, Jekyll), site (MkDocs).

For this app the build is a copy, because plain HTML needs no compilation:

build_command: "mkdir -p dist && cp index.html style.css dist/"

Where your build_command runs

Your build_command runs in an isolated build container, separate from the machine that clones your repository and uploads your site. What that container gives you:

You get Details
Your repository A full copy at the working directory, including .git, so git describe works. Your .dockerignore is not applied: it is for your container images, and ignoring files here would strip your site's sources.
Node.js 20 and Python 3 The builder image is node:20-bookworm. python3 -m venv works, so MkDocs and other Python generators can install their requirements.
Your app's variables Every variable you set with mecca var set, and the service's environment: values (with ${service:…} resolved), exactly as before.
Internet access npm install, pip install and other package downloads work normally.

What it does not give you, by design: AWS credentials, the cloud metadata endpoint, the Docker socket, the platform's git credentials, or any platform secret. A build step that tried to read these (for example an aws s3 cp inside build_command) will fail. If you need something private during the build, set it as an app variable with mecca var set and read it from the environment inside your build tool.

The build log prints your build_command exactly as you wrote it, with $VARIABLE names left unexpanded, so naming a secret variable in the command does not show its value.

Symbolic links in output_dir. A link that points to something inside your build (for example latest -> v1/) is uploaded as a real copy of its target. A link that points outside the build, or to nothing, fails the build with an ERROR: line naming it.

If your app has both a static site and container services, your containers are built separately and cannot see the static build's output directory.

⚠ Variable names must be valid shell identifiers (letters, digits and _, not starting with a digit). A variable named MY-VAR or 1TOKEN is skipped for the static build, with a warning in the build log.

spa_fallback — off here, on for single-page apps

spa_fallback: false

With spa_fallback: true, the edge cache serves index.html (status 200) for any path that is not a real file, so a client-side router can handle deep links like /settings/team.

This site has no router — every page is a real file — so it stays false, and a genuinely missing path correctly returns the error_document. Turn it on for React, Vue or Svelte SPAs. See React Frontend.

No health checks, and why

A container has to prove it started before the router will send it traffic. A static site has no container and nothing for the router to target — the files are objects in storage, served by the edge cache — so there is nothing to health-check and no /health endpoint to write.

When to use type: static

Use it whenever the thing you are deploying is files, with no server-side code:

  • Marketing and landing pages
  • Documentation sites (MkDocs, Hugo, Jekyll)
  • Single-page apps (React, Vue, Svelte) — add spa_fallback: true

If your app runs a process to serve requests — Express, Django, Rails, or SvelteKit with adapter-node — it is not static and does need a container. See Service types.

What's Next?