Skip to content
Better 404 pages for App Engine static websites

Better 404 pages for App Engine static websites

May 1, 2026

There’s a semi-documented feature in App Engine’s static files handlers that can be super useful: require_matching_file: true. The documentation for app.yaml’s static handlers does not mention this field, but we can find it in the RPC docs for the App Engine Admin API.

require_matching_file - Whether this handler should match the request if the file referenced by the handler does not exist.

I find that definition hard to parse, here’s my attempt: when true, the requested file must exist in order for a request to match the handler; if the file does not exist, then the request will skip this handler.

The default behaviour is equivalent to require_matching_file: false. Suppose you have an app with static HTML generated for upload in a “dist” directory, and the default main.py as your Python script:

# app.yaml
runtime: python314
handlers:
  - url: /  # Match a request for anything
    static_dir: dist

A request for “/foo.html” will match the first handler. If “dist/foo.html” exists, it will be served. If “dist/foo.html” does not exist, then the user will see App Engine’s default 404 response.

But specifying require_matching_file: true changes the behaviour to fall through to the next handler if there is no file:

# app.yaml
runtime: python314
handlers:
  - url: /  # Match a request for anything
    static_dir: dist
    require_matching_file: true  # But only match if the requested file exists
  - url: /.*  # All other requests
    script: automatic

Now, a request for “/foo.html” matches the pattern for the first handler, but fails the match when “dist/foo.html” does not exist. But instead of returning a 404 response, App Engine sees if the next handler will match. The next handler in this case is the Python script at main.py, which gives you an opportunity to return a nicer looking, custom 404 response (or a redirect, or a 200, or whatever).

This is cool. You can use App Engine’s static files handlers to serve all the static content, but when there’s no match, have the dynamic script handler respond with a pretty 404. Generating a response with a dynamic handler is going to be slower than a response from a static handler, but gives you all the flexibility.

Last updated on