---
title: React, NestJS et PostgreSQL
description: Mettre en pratique les images, volumes, réseaux, ports et dépendances.
---

Cet exemple rassemble un frontend React/Vite, un backend NestJS, une base PostgreSQL et Nginx.

## Dockerfile du backend NestJS

```dockerfile
# Stage 1 - build
FROM node:25-slim AS builder
WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci

COPY . .
RUN npm run build

# Stage 2 - production
FROM node:25-slim
WORKDIR /app

COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
COPY --from=builder /app/scripts ./scripts

CMD ["node", "dist/src/main"]
```

Le premier stage compile le TypeScript. Le second ne récupère que les fichiers nécessaires au runtime.

## Dockerfile du frontend React/Vite

```dockerfile
# Stage 1 - build
FROM node:25-slim AS builder
WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci

COPY . .
RUN npm run build

# Stage 2 - production
FROM node:25-slim
WORKDIR /app

RUN npm install --global serve
COPY --from=builder /app/dist ./dist

CMD ["sh", "-c", "serve -s dist -l ${FRONTEND_CONTAINER_PORT}"]
```

Un build Vite produit des fichiers statiques. Le support propose de générer un `config.json` au démarrage à partir des variables d'environnement, avant de servir `dist/`. Une même image peut ainsi recevoir plusieurs configurations runtime sans être reconstruite.

Pour PostgreSQL, aucun Dockerfile n'est nécessaire : l'image officielle `postgres:16-alpine` suffit.

## Fichier Compose de développement

```yaml
name: mon-app-dev

services:
  postgres:
    image: postgres:16-alpine
    networks:
      - app-network
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}
      interval: 5s
      timeout: 5s
      retries: 5

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - app-network
    volumes:
      - ./backend:/app
      - /app/node_modules
    environment:
      POSTGRES_HOST: postgres
      POSTGRES_PORT: 5432
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}

  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    depends_on:
      - backend
    networks:
      - app-network
    volumes:
      - ./frontend:/app
      - /app/node_modules

  nginx:
    image: nginx:1.27-alpine
    ports:
      - "${NGINX_SECURE_HOST_PORT}:443"
    depends_on:
      - frontend
      - backend
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  postgres_data:
```

## Ce que l'exemple met en œuvre

| Concept | Emplacement |
| --- | --- |
| Image existante | `postgres:16-alpine` et `nginx:1.27-alpine` |
| Image custom | `build:` pour le backend et le frontend |
| Build puis run | Compose construit les images et instancie les conteneurs |
| Persistance | `postgres_data` conserve la base |
| Hot-reload | `./backend:/app` et `./frontend:/app` |
| Réseau | Tous les services partagent `app-network` |
| DNS interne | Le backend utilise `POSTGRES_HOST=postgres` |
| Ports | Seul Nginx publie un port |
| Démarrage ordonné | Le backend attend le healthcheck PostgreSQL |

## Flux d'une requête

```text
navigateur
    │
    ▼
port HTTPS publié par Nginx
    │
    ├──► frontend React
    │
    └──► backend NestJS ──► PostgreSQL
```

Un seul port est exposé. Tout le trafic externe entre par Nginx ; les autres communications restent dans le réseau privé Docker.

## Lancer la stack

```bash
docker compose -f docker-compose.dev.yml up --build
```
