service "web" refers to undefined network backend: invalid compose project — a service lists a network, backend, under its networks: key, and the Compose file has no top-level networks: section that declares it. Add the declaration and the project starts.

The fix is a top-level networks: section at the end of the file with the network's key followed by a colon, plus an optional name: line for the network's name on the engine. Then run docker compose up -d again.

The error

PS> docker compose up -d
service "web" refers to undefined network backend: invalid compose project

The command exited with code 1. docker compose config printed the same line and also exited with code 1, so the file can be checked without starting anything. The file that produced it:

name: fix9-cmp-c3
services:
  web:
    image: alpine
    command: ["sleep", "300"]
    networks:
      - backend

Why it happens

A word in a service's networks list is the key of a network, and that key has to appear under the top-level networks: section of the same file. Here it was not, and Compose rejected the project before it created a network or a container.

This shows up after copying one service out of a longer file, where the declaration stayed behind, or after a typo between the service's line and the declaration. The message names both the service and the missing key, so search the file for that key.

The fix

name: fix9-cmp-c3
services:
  web:
    image: alpine
    command: ["sleep", "300"]
    networks:
      - backend
networks:
  backend:
    name: fix9-cmp-backend
PS> docker compose up -d
 Network fix9-cmp-backend Creating
...
 Network fix9-cmp-backend Created
...
 Container fix9-cmp-c3-web-1 Started
PS> docker network ls --filter name=fix9-cmp-
NETWORK ID     NAME               DRIVER    SCOPE
a1467a5d4857   fix9-cmp-backend   bridge    local

Compose created the network under the name from the name: line, as a bridge network, and started the container on it. A later docker compose down -v removed the container and the network. The name: line is optional; it sets the network's name on the engine, which helps when you look the network up with docker network ls as above. A network shared with another project is declared differently, with external: true, and has its own error, covered in the post linked below.

How it was reproduced

One alpine service running sleep 300 with backend in its networks list and no top-level networks: section, started with docker compose up -d from Windows PowerShell 5.1 on Docker Engine 29.9.3 and Docker Compose v5.7.0 (Docker Desktop on Windows 11). The project and network names carry this test's fix9-cmp- prefix. The project was removed with docker compose down -v.

Frequently asked

What does 'refers to undefined network' mean in Docker Compose?
A service lists a network under its networks key and the file has no top-level networks section that declares that name. Compose rejects the project and creates nothing.
How do I declare a network in docker-compose.yml?
Add a top-level networks: section with the network's key followed by a colon, for example backend:. A name: line under it is optional and sets the network's name on the engine.
Can I check a Compose file for undefined networks without starting it?
Yes. docker compose config printed the same 'refers to undefined network' line and exited with code 1 in this test, without creating anything.

More decoded errors in the Fixes category. The same message for a named volume is Docker Compose: service refers to undefined volume, and for a network marked external that does not exist, see network declared as external, but could not be found.