Every application built on Gingee follows a simple and consistent structure. This guide breaks down that structure, explains the critical role of the box folder, and provides a comprehensive reference for all the settings available in the app.json and routes.json configuration file.
Every first-level directory inside your server's web root is considered a distinct App. For an application named my_app, the structure looks like this:
web/
└── my_app/
├── box/
├── css/
├── images/
├── scripts/
└── index.html
my_app/: The root folder for the application. The name of this folder becomes the app's unique ID and the first segment of its URL (e.g., http://localhost/my_app/...).
css/, images/, scripts/, etc.: These are public directories. Any file placed here can be accessed directly by its URL. Gingee's static file server will serve these assets. For example, a file at web/my_app/css/style.css is available at /my_app/css/style.css.
index.html: If a user navigates to the app's root URL (/my_app), this file will be served by default (if the app is not an SPA).
box FolderThe box folder is the private, secure core of your application. It contains all your backend logic, configuration, and private data.
Security: The box folder is always protected. No file inside the box can ever be accessed directly from a URL. A request to /my_app/box/app.json, for example, will be blocked with a 403 Access Denied error. This is a fundamental security guarantee of the Gingee platform.
Server Scripts: All your backend API endpoints are JavaScript files that live inside the box. A request to /my_app/api/users is mapped to the file at web/my_app/box/api/users.js.
Configuration: All app-specific configuration, including the crucial app.json file, resides in the box.
Private Data: If your application uses a file-based database like SQLite, its database file should be stored in a subdirectory within the box (e.g., box/data/app.db) to ensure it is protected from direct web access.
app.json File:The app.json file, located at web/my_app/box/app.json, is the central configuration file for your application. It tells the Gingee server how to handle the app, what resources it needs, and how it should behave.
Here is a comprehensive breakdown of all available properties.
{
"name": "My Awesome App",
"description": "This is a demonstration of all app.json settings.",
"version": "1.2.0",
"type": "MPA",
"mode": "production",
"spa": {
"enabled": false,
"dev_server_proxy": "http://localhost:5173",
"build_path": "./dist",
"fallback_path": "index.html"
},
"db": [],
"startup_scripts": [],
"default_include": [],
"env": {},
"jwt_secret": "a-very-strong-and-unique-secret-key",
"cache": {
"client": {
"enabled": true,
"no_cache_regex": ["/api/realtime"]
},
"server": {
"enabled": true,
"no_cache_regex": ["/api/dynamic-script.js"]
}
}
}
name (string, required)description (string, optional)version (string, optional)type (string, optional)
"MPA" (Multi-Page Application): The default."SPA" (Single Page Application - NOT IMPLEMENTED YET): Activates "SPA Fallback" for client-side routing.mode (string, optional)
"production" (Default): The standard mode for live servers. For SPAs, this serves the compiled static assets from the build_path."development" : Activates development-only features. For SPAs, this enables the seamless dev server proxy.spa object)This object is only used when app is of "type": "SPA".
spa.enabled (boolean, required): Must be true to activate SPA features.spa.dev_server_proxy (string, optional): (Development only) The full URL of your frontend's hot-reloading development server (e.g., Vite, Angular CLI). Gingee will proxy all non-API requests to this URL when the app's mode is "development".spa.build_path (string, required): (Production only) The path to the directory containing your compiled frontend assets, relative to the app's root folder (e.g., ./dist).spa.fallback_path (string, required): (Production only) The path to the SPA's entrypoint file (usually index.html) within the build_path. Gingee serves this file for any request that doesn't match an API route or a static asset, enabling client-side routing.db (array, optional)
type, name, host, user, password, database, etc.startup_scripts (array, optional)
box folder."startup_scripts": ["setup/01_schema.js", "setup/02_seed_data.js"]default_include (array, optional)
"lib/auth.js"), it is resolved as a path relative to the app's box folder."auth"), it is resolved from the global modules folder."default_include": ["auth_middleware.js", "lib/request_logger.js"]env (object, optional)
$g.app.env.jwt_secret (string, optional)
auth module for creating and verifying JSON Web Tokens (JWTs).cache (object, optional)
cache.client: Controls browser caching (Cache-Control header).cache.server: Controls server-side caching of static files and transpiled scripts in Memory or Redis.pmft.json File (Permissions Manifest)If you plan to distribute your application as a .gin package, you must declare the permissions it requires in a pmft.json file. This manifest is read by the gingee-cli during the installation process to request consent from the server administrator.
web/<your-app-name>/box/pmft.jsonmandatory) and optional (optional) permissions.For a complete guide on the permissions system and the structure of this file, please see the Gingee Permissions Guide MD HTML.
routes.json File (Manifest-Based Routing)For applications that require more powerful and flexible routing, such as RESTful APIs with dynamic path parameters, you can create a routes.json file. When this file is present in an app's box folder, it activates manifest-based routing, which takes precedence over the default file-based routing.
web/my-app/box/routes.jsonroutes.jsonThe file must contain a single root object with a routes key, which holds an array of route definition objects.
{
"routes": [
{
"path": "/users",
"method": "GET",
"script": "users/list.js"
},
{
"path": "/users/:userId",
"method": "GET",
"script": "users/get.js"
},
{
"path": "/users/:userId",
"method": "PUT",
"script": "users/update.js"
},
{
"path": "/:category/:slug/images/:imageId?",
"method": "GET",
"script": "content/view.js"
}
]
}
Each object in the routes array defines a single endpoint and has the following properties:
path (string, required)
:), followed by its name (e.g., :userId). The name should use standard variable naming conventions.?) to its name (e.g., :imageId?).*) as a wildcard to match the rest of a path.method (string, optional)
GET.GET, POST, PUT, DELETE, PATCH. You can also use ALL to match any method for a given path.script (string, required)
box folder. The .js extension is optional."script": "api/users/get-profile" will execute the file at web/my-app/box/api/users/get-profile.js.When a route with dynamic parameters is matched, Gingee automatically parses the values from the URL and makes them available in your server script via the $g.request.params object.
Example:
routes.json:
{ "path": "/products/:productId/reviews/:reviewId", "script": "reviews/get.js" }
/my-app/products/abc-123/reviews/42box/reviews/get.js):
module.exports = async function() {
await gingee(async ($g) => {
const productId = $g.request.params.productId; // "abc-123"
const reviewId = $g.request.params.reviewId; // "42"
$g.response.send({
message: `Fetching review ${reviewId} for product ${productId}.`
});
});
};