Skip to main content
Every Fymo app is shaped the same way. Once you know this map, you know your way around any Fymo project, including the one you’re about to build. One directory lives outside app/ and still shapes it: .fymo/templates/ holds project-local overrides for the generator templates. A file there at the same relative path as a packaged template wins over it, so a team’s conventions ride along in the repo. fymo generate templates publishes the packaged tree there for editing; see Generators.
The examples/ apps in the Fymo repo are pure generator output now. Reading one is reading exactly what fymo new and fymo generate produce today, which makes them a reliable reference for this layout.

Task registries

Files under app/jobs are meant to stay thin. Think of it as a handful of submittable entry points, not a place where implementation piles up. Every top-level function without a leading underscore becomes a submittable task automatically. Mark the ones you mean as entry points with @task so that’s explicit, and prefix any helper you don’t want exposed with an underscore.
Adding @task doesn’t change what gets discovered. An undecorated top-level function is still registered exactly as before, for backward compatibility. The decorator just makes a module read the same way regardless of habit, and lets Fymo nudge you toward it with a log message instead of silently guessing.

Safety net, not a trap

Fymo watches for a couple of easy mix-ups so you don’t have to. Say a Svelte file ends up in the controllers folder, or a Python file ends up in templates or components. The build catches it immediately. Both fymo build and fymo dev will tell you exactly what’s misplaced, right when you save.
Without this check, Python would simply never import a stray .svelte file, and esbuild would never bundle a stray .py file. You’d just have a feature that quietly does nothing. Hearing about it the moment you save beats hunting for it later.
A .py file under app/lib gets the gentle version of this: not a blocked build, just a friendly suggestion in the terminal that it probably belongs in app/support instead. app/lib is the $lib/* alias for TypeScript and Svelte imports, so Python placed there never runs. Fymo is just looking out for you.
Stylesheets get the same treatment. They’re build inputs, not something you drop into a template folder: they live in app/assets, imported explicitly from a layout, like import '../assets/app.css' in app/templates/_layout.svelte. A loose .css file anywhere under app/templates fails the build with stylesheets live in app/assets/, found <path>. <style> blocks inside a .svelte file are untouched, that’s Svelte’s own component styling and none of this check’s business.
Coming from an older Fymo project, app/templates/_global.css used to be picked up automatically. It isn’t anymore. A project still shipping that exact file fails the build with the exact fix:
For the full pipeline, fonts, and how nested layouts compose their CSS, see Assets, fonts, and static files. This page is just the map, that one’s the walkthrough.

Where identity lives

app/auth is where @identify resolvers decide who’s making a request. Fymo auto-discovers every module there the same way it discovers app/remote, just through a separate glob, one is never mistaken for the other. Run fymo generate auth to scaffold a resolver and the login flow around it. Delete the whole directory and identity resolution turns off, nothing else needs to change. That’s the placement story. For resolvers, current_uid(), route guards, and testing with signed_in(), see Authentication.

One line, three homes

If a file’s home is ever unclear, one line covers most of it. In git and compiled with the app, it belongs in app/assets. In git and served exactly as it sits on disk, it belongs in app/static. Created after the app is deployed, it belongs in storage, not in git at all. See Storage and media for that last one.