← Open Source
ai skill

utopia-cms

The skill that stops a Flutter admin being hand-rolled - declare your columns as entries, point a delegate at Firebase, Supabase, or Hasura, and the table, CRUD, and filters come with it.

/plugin marketplace add Utopia-USS/utopia-flutter-skills /plugin install utopia-cms@utopia-flutter-skills
flutter pub add utopia_cms
why it exists
Every internal tool grows the same screen by hand: a DataTable, a Firestore or Supabase service behind it, the useState<List<T>?> plus isLoading plus error triplet, and a bespoke form per entity. One such admin screen runs about 970 lines. On utopia_cms the same screen is about 80. This is the skill that keeps our agents - and your team - from rebuilding the 970-line version: you declare what data you have as entries and where it lives as a delegate, and the table, the create/edit/delete overlay, the filters, and the per-row actions are rendered for you.

The backends are prebuilt - Firebase, Supabase, and Hasura ship as ready delegates, and for any other GraphQL backend the GraphQL building block gets you a working delegate in about thirty lines. The skill carries the patterns and the honest edges with them: the known limitations of the current package are written down, so an agent works around the Firestore read override or the offset-paging caveat instead of discovering it in your data. We publish all of this, so you can read how the admin gets built before you hire us - and it is the same skill your team keeps after hand-over.
utopia-cms/SKILL.md11 refs
name
utopia-cms
Referencesshell → table → delegate
Anti-patternsCRITICAL
CmsWidget shellCRITICAL
CmsTablePageCRITICAL
DelegatesCRITICAL
EntriesCRITICAL
FiltersHIGH
Table actionsHIGH
Management sectionsHIGH
ThemeMEDIUM
RelationshipsMEDIUM
MediaMEDIUM
Read the full skill
usage

Declare what you have, point at where it lives, get the table:

CmsTablePage(
  title: "Users",
  // where it lives: point a prebuilt delegate at your backend.
  delegate: CmsFirebase.delegate(collection: "users"),
  // what you have: declare the columns as entries.
  entries: [
    CmsTextEntry(key: "name", modifier: const CmsEntryModifier(sortable: true)),
    CmsTextEntry(key: "email", modifier: const CmsEntryModifier(editable: false)),
    CmsBoolEntry(key: "active"),
  ],
);
// The outcome: a paged, sortable table with a create / edit / delete
// overlay and per-row actions - no DataTable, no service, no loading flags.
talk to us

Want this in your build?

The team behind utopia-cms ships production Flutter on the same stack. Tell us what you are building.