Self-hosted, Nuxt-powered web app to manage cooklang recipes, create a shopping list, fill a cart with matching products and send it to an online store. Using the @tmlmt/cooklang-parser Typescript parser, in its v3 version (alpha stage).
The app is currently in pre-v1 i.e beta version and in active development. Only recipe management (browsing, viewing, creating, editing) and shopping lists are functional at the moment while the rest is partially developed and therefore hidden an experimental flag. Feel free to test it out and report issues or feature requests.
- File & folder based β recipes live as plain
.cooktext files in regular directories β easy migration from/to other Cooklang-compatible tools - Full spec compatibility β powered by
@tmlmt/cooklang-parser, with support for many useful extensions such as references, recipe variants, alternative ingredients, etc.
- Browse recipes β navigate your Cooklang recipe collection in a folder structure with grid or list view
- View recipes β read recipes with ingredients, cookware, preparation steps, metadata (tags, author, source, time), and variant support
- Create, edit, move & delete recipes β full CRUD with in-app Cooklang editor and syntax validation
- Recipe images β upload cover and per-step images, displayed in a carousel; powered by Nuxt Image with on-the-fly optimization
- Servings scaling β dynamically adjust ingredient quantities by changing the serving count
- Recipe search β fuzzy command-palette search across titles, tags, author, and description (β/CTRLK)
- Download
.cookfiles β export any recipe as a Cooklang file - Cook mode β full-screen step-by-step walkthrough with swipe navigation, progress bar, per-step ingredients/cookware, and built-in countdown timers with browser notifications
- AI recipe converter β convert any recipe to Cooklang directly in the editor: import from a URL or paste raw text and let an AI model produce the
.cookfile (opt-in, compatible with OpenAI/LocalAI and Anthropic APIs)
- Per-recipe visibility β mark individual recipes as public or private (configurable default)
- Share links β generate time-limited tokens that let anyone view a recipe without logging in
- Public browsing β optionally allow unauthenticated visitors to browse all public recipes
- Atom feed β expose public recipes via an Atom/XML feed for RSS readers and federation (opt-in)
- π Self-hosted β runs on your own server with a single Node.js process and SQLite database
- π Role-based authentication β two roles (editor and viewer) with password auth (scrypt-hashed) and/or OIDC single sign-on
- π Dark / light mode β toggle between color themes
- π± Responsive design β optimized for both desktop and mobile
- Custom app title β configurable application name shown in the header and SEO tags
- π‘οΈ Security hardening β built-in HTTP security headers (CSP with nonce, HSTS, X-Frame-Options), request size limiting, rate limiting, and SRI via nuxt-security
Opt-in: requires
shopping.enabled: true(or"editor-only") inconfig.yaml.
- User-specific list β add recipes from the browse view with per-recipe serving adjustments; add or remove free-hand items not tied to any recipe
- Store Run mode β fullscreen checklist with a progress bar to tick off ingredients while shopping. Live updates of changes made by the list owner (e.g. new ingredients/recipes added) or any store runner (e.g. ingredients checked or unchecked).
- Share links β generate time-limited (or permanent) links that let anyone view your current shopping list without logging in; logged in users can edit it; all recipients can also use Store Run mode
- Pantry management β define a per-user pantry in TOML format; pantry items are automatically deducted from the shopping list so ingredients you already have at home never appear
- Category configuration β define a per-user ingredient categorization file to group shopping list items by aisle or category (e.g. Dairy, Bakery, Produce); uncategorized items fall into "Other"
Requires
experimental: trueinconfig.yaml.
- π Shopping cart β match aggregated ingredients against a product catalog (TOML-based) and identify unmatched items
- Node.js (v22 or later)
-
Download the latest release tarball from the releases page
-
Extract it to your desired installation directory:
mkdir -p /path/to/cooklang-shopper tar -xzf cooklang-shopper-v*.tar.gz -C /path/to/cooklang-shopper -
Create your configuration file by copying the provided example:
cd /path/to/cooklang-shopper/dist cp config.yaml.example config.yaml -
Edit
config.yamlβ set the different parameters (see the file for instructions). For password authentication, generate hashed passwords for the editor and viewer roles:node hash-password.mjs <editor-password> node hash-password.mjs <viewer-password>
For OIDC authentication, configure the
oidcblock with your identity provider's client credentials, issuer URL, and role mapping. Roles are assigned based on an OIDC claim in the token β either via scopes granted by the IdP or via group membership. Seeconfig.yaml.examplefor detailed examples of both strategies. Multiple OIDC providers can be configured, and password + OIDC can be enabled simultaneously.The
sessionSecretfield is required (minimum 32 characters). Generate one with:openssl rand -base64 32
For OG image URL signing, set
NUXT_OG_IMAGE_SECRETas an environment variable β add it to your.envfile or process manager config (e.g. a pm2 ecosystem file). A secret is auto-generated at startup if omitted, but setting it explicitly ensures stable signed URLs across restarts. Alternatively, setogImageSecretdirectly inconfig.yaml. -
Add your
.cookrecipe files todist/public/recipes/ -
Start the server once to initialize the database (created automatically at
dist/data/cooklang-shopper.db) -
Set up the systemd service:
# Edit the service file to adjust User, WorkingDirectory, and ExecStart paths sudo cp /path/to/cooklang-shopper/dist/cooklang-shopper.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now cooklang-shopper
Alternatively, start the server manually:
cd /path/to/cooklang-shopper/dist node server/index.mjs
In line with the file-first approach of the cooklang ecosystem, shopping lists, pantry files and category configuration files are plain text files stored on the server. Each file is scoped to a specific user via a user key derived from their login credentials:
- For password authentication:
password-{username}(dots in the username replaced with underscores) - For OIDC authentication:
{provider}-{userId}(dots in either part replaced with underscores)
| Feature | Directory | Filename pattern | Format |
|---|---|---|---|
| Shopping list | dist/public/recipes/ |
.shopping-list.{userKey} |
Cooklang shopping list |
| Checked items | dist/public/recipes/ |
.shopping-checked.{userKey} |
Plain text |
| Pantry | dist/public/pantry/ |
pantry.{userKey}.conf |
TOML |
| Category config | dist/public/categories/ |
category-config.{userKey}.conf |
Cooklang category DSL |
The two latter ones can be edited in-app (Pantry page for the pantry; Category Config in the shopping list menu). You can also create or pre-populate them directly on the server before users log in. Refer to the Cooklang conventions for the expected file formats.
The release tarball includes an upgrade.sh script at the root of the installation directory. It downloads the latest release, replaces the application files, and restores your recipes, product catalog, and config.yaml automatically.
cd /path/to/cooklang-shopper
./upgrade.shOptions:
--edgeβ include pre-releases when finding the latest version--tag <tag>β download a specific version (e.g.--tag v1.0.0)
The previous version is kept in dist.bak/ for easy rollback:
rm -rf dist && mv dist.bak distRollback preserves all user data including the database. If a newer version added schema changes, the older version safely ignores them.
Note: Stop the server before upgrading and restart it afterward.
sudo systemctl stop cooklang-shopper ./upgrade.sh sudo systemctl start cooklang-shopper
- Internationalization (i18n)
- Finalize shopping cart features
- Develop feature to send cart to a pre-configured online store
- Add customization possibilities

