Skip to content

Directory structure

rocambille edited this page May 4, 2026 · 3 revisions

Summary: The default structure of a StartER application is a starting point. You are free to organize your application however you like. StartER imposes no constraints on the location of an element, as long as you adapt the code to your organization: you have control!

File organization

StartER offers a robust, yet non-strict starting structure. The goal is to have a clear organization for your frontend and backend files, as well as the configuration.

Detailed view of StartER

.
├── .env
├── .env.sample
├── compose.yaml
├── compose.prod.yaml
├── Dockerfile
├── index.html
├── server.ts
└── src
    ├── entry-client.tsx
    ├── entry-server.tsx
    ├── database
    │   ├── data
    │   │   └── database.sqlite
    │   └── schema.sql
    ├── express
    │   ├── routes.ts
    │   ├── helpers
    │   │   └── ...
    │   └── modules
    │       └── ...
    ├── react
    │   ├── routes.tsx
    │   ├── helpers
    │   │   └── ...
    │   └── components
    │       └── ...
    └── types
        └── index.d.ts

You can use the make:clone script provided with StartER to duplicate part of this structure and create new modules or components. This script does not impose any opinionated templates; it allows you to replicate your own structures and best practices.

The root directory

The .env files

StartER uses a .env file to separate environment variables from code. During a fresh installation of StartER, your application's root directory will contain a .env.sample file that defines common environment variables. This file serves as a common template for sharing necessary variables without exposing sensitive information. After installing StartER, copy this .env.sample file as .env.

cp .env.sample .env

Here are the recommended variables that you should fill in with your own values:

Variable Description
APP_BASE_URL Base URL of the application (used for magic links).
APP_SECRET Secret key used to generate the signature for authentication
APP_PORT (Optional) Port for the application server (5173 by default)
SMTP_URL (Optional) SMTP URL for sending emails (e.g., smtp://mailpit:1025)

A minimal version of your local .env file for development could look like this:

APP_BASE_URL=http://localhost:5173
APP_SECRET=18a7a18ac0db9b781836f82c080e1c82314b9b56b51f9a914c39cc41113280e8

Note

Thanks to its Zero-Config architecture with SQLite, StartER does not require any complex configuration variables for the database.

Tip

To generate a robust APP_SECRET, you can use the following command in your terminal:

openssl rand -hex 32

Also in your .env file, you can add:

  • more variables for third-party tools you have installed,
  • your own variables.

To start your application, StartER uses tsx (which uses the node command under the hood) with the --env-file option to load your .env file. Your variables are then available in process.env.

You can edit the tsx command options in the scripts in the package.json file at the root of the project.

{
  "scripts": {
    "dev": "tsx --env-file=.env server",
    "start": "tsx --env-file=.env server",
    ...
  },
  ...
}

For example, you can pass multiple --env-file arguments to build a more complex configuration with multiple .env files (.env.local, .env.prod, etc.). Refer to the --env-file documentation for more details.

Docker files

According to the official documentation:

Docker provides the ability to package and run an application in a loosely isolated environment called a container.
[...] A container is a runnable instance of an image.
[...] To build your own image, you create a Dockerfile with a simple syntax for defining the steps needed to create the image and run it.

A Dockerfile defines the contents and startup behavior of a single container. A StartER application image is based on an Alpine Linux image with the latest LTS version of Node.js pre-installed.

ARG NODE_VERSION=24

FROM node:${NODE_VERSION}-alpine

The Dockerfile copies your StartER application sources into this image, installs dependencies, and runs the npm run dev command.

COPY . .

# Run the application.
CMD ["npm", "run", "dev"]

The .dockerignore file excludes files not needed to build the image (such as README, LICENSE...).


Docker is optional but recommended. Additionally, a compose.yaml file allows you to define a multi-container application. In an isolated network, the StartER compose.yaml file defines:

  • a server container for your StartER application,
  • a mailpit container to locally capture emails sent by the application (without complex configuration).

To create and start the containers in development mode, run the command:

docker compose up --build

More options are available in the docker compose up documentation.

The compose.prod.yaml file specializes the containers for production:

  • The NODE_ENV environment variable is set to production.
  • The server container is started with npm run build && npm start, rather than npm run dev.

To create and start the containers in production mode, run the command:

docker compose -f compose.prod.yaml up --build

The index.html file

The index.html file references entry-client and includes a <!--ssr-outlet--> tag where the server-rendered markup is injected (see explanation about the [one server] of StartER for details [warning: the page is more technical than the rest of the wiki]).

Also, the index.html file is the anchor point for Pico CSS by linking the library and adjusting some basic variables.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Start Express React</title>
    <link
      rel="shortcut icon"
      href="/src/react/assets/images/favicon.png"
      type="image/png"
    />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
    />
    <style>
      :root {
        --pico-border-radius: 2rem;
        --pico-form-element-spacing-vertical: 0.5rem;
        --pico-form-element-spacing-horizontal: 1rem;
      }
    </style>
  </head>
  <body>
    <div class="container" id="root"><!--ssr-outlet--></div>
    <script type="module" src="/src/entry-client"></script>
  </body>
</html>

Refer to the Pico CSS documentation for a list of available variables.

The server.ts file

The server.ts file is the entry point to the framework. Its code bridges the gap between an Express server and a Vite server to create one server.

The src directory

Most of your StartER application is hosted in the src directory. By default, the src directory contains the following directories:

  • database,
  • express,
  • react,
  • types.

The express and react directories are the heart of your StartER application. They are organized in a similar way:

  • A helpers folder contains infrastructure tools (cache, mutations, validation, converters).
  • A modules (Express) or components (React) folder contains your business logic and UI.
  • A routes file centralizes the registration of all endpoints or pages in the application.

The database directory contains your database schema (schema.sql), an optional seeder (seeder.sql), the SQLite database declaration, and most importantly, the data/ subdirectory which will host the local database.sqlite database file generated on the fly.

The types directory contains the TypeScript type definitions shared throughout your StartER application.

These directories form the basis of your StartER application.

Best practices and use cases

  • Share non-sensitive variables: you can include additional variables in your StartER application's .env.sample file. By adding entries to the .env.sample file, other developers on your team can clearly identify the environment variables required to run your application.
  • Never commit secrets: your .env file should never be added in a Git commit. Each workstation (local machine or server) running the application may require a different environment configuration. Furthermore, this would pose a critical security risk.
  • Ignore your local database: the src/database/data/ directory containing database.sqlite is intentionally ignored by Git via the .gitignore file. Do not commit it to avoid overwriting the local data of other developers.

See also

Clone this wiki locally