organize-project

Organise documents into folders and move them between folders and modules with MOVE. Use when a module has grown unstructured, when restructuring a project, or when a document is in the wrong place.

SKILL.md

GitHub
<!-- skill-index: generated by scripts/skill-index.py; make check-skill-index -->

Find it fast

sed -n '<from>,<to>p' SKILL.md one section rather than reading the file; ./mxcli syntax <topic> answers how do I write this for a fraction of either.

lines section
30-38 When to Use This Skill
39-73 Folder Conventions
74-133 Creating Documents in Folders
134-174 Reading the Layout Back
175-223 Moving Documents
224-231 Folder Rules
232-287 Supported Document Types
288-318 Example: Reorganize a Module
319-337 Moving Folders
338-354 Deleting Folders
355-362 Validation Checklist
<!-- /skill-index -->

Project Organization: Folders and Moving Documents

This skill covers organizing Mendix project documents (pages, microflows, snippets, nanoflows) into folders and moving them between folders and modules.

When to Use This Skill

Use this skill when:

  • Organizing documents into folder hierarchies within a module
  • Moving documents between folders
  • Moving documents between modules
  • Restructuring a project for better maintainability
  • Setting up folder conventions for a new module

Folder Conventions

Organize by functional grouping — keep all artifacts for a feature together, not separated by document type. This way, a developer working on "Customer" finds everything in one place: pages, microflows, snippets, and validation logic.

Recommended folder structure within a module:

CRM/
├── Customer/
│   ├── Customer_Overview        -- Overview page
│   ├── Customer_NewEdit         -- Edit page
│   ├── CustomerCard             -- Snippet
│   ├── ACT_Customer_Save        -- Save microflow
│   ├── ACT_Customer_Delete      -- Delete microflow
│   ├── ACT_Customer_New         -- New microflow
│   ├── VAL_Customer             -- Validation microflow
│   └── DS_Customer_Filter       -- Data source microflow
├── Order/
│   ├── Order_Overview
│   ├── Order_NewEdit
│   ├── ACT_Order_Save
│   └── VAL_Order
└── Shared/                      -- Cross-cutting concerns
    ├── SUB_SendNotification
    └── Navigation_Snippet

Why functional grouping over type grouping:

  • All related artifacts are in one place — easier to navigate and review
  • Adding or removing a feature is a single folder operation
  • Naming prefixes (ACT_, VAL_, SUB_, DS_) already indicate document type
  • Mirrors how developers think: "I'm working on Customer" not "I'm working on microflows"

Adapt to your project's conventions. The key is consistency across modules.

Creating Documents in Folders

Microflows

Use the folder keyword after the return type, before begin:

mdl 1;
create microflow MyModule.ACT_ProcessOrder ($Order: MyModule.Order)
returns boolean as $success
folder 'Order'
begin
  commit $Order;
  return true;
end;

Pages

Use the folder property inside the page properties:

mdl 1;
create page MyModule.Customer_Overview folder 'Customer'
(
  title: 'Customer Overview',
  layout: Atlas_Core.Atlas_Default
)
{
  -- widgets
};

Snippets

mdl 1;
create snippet MyModule.CustomerCard folder 'Customer'
{
  -- widgets
};

Nested Folders

Use / to create nested folder paths. Missing folders are created automatically:

mdl 1;
-- Creates 'Order', then 'Order/Batch' if they don't exist
create microflow MyModule.ACT_BatchProcess ($list: list of MyModule.Order)
folder 'Order/Batch'
begin
  loop $Order in $list begin
    commit $Order;
  end loop;
  return;
end;

Reading the Layout Back

list folders shows the folder layout of a module and what is in each folder. This is the counterpart to move: move puts a document somewhere, list folders shows where everything actually is.

-- One module
list folders in MyModule;

-- Every module in the project
list folders;
MyModule
  (module root)  [1]
    Microflow ACT_Unfiled
  Api  [0]
  Api/Published  [1]
    ODataService PublicApi
  Support  [1]
    JavaAction Helper

(3 folder(s), 3 document(s))

Three things about the output are deliberate:

  • Empty folders are listed (Api [0]), so the listing is the whole layout and can be diffed against an intended one.
  • Documents still at the module root appear under (module root) — what is not filed yet is the thing you most want to notice.
  • Ordering is stable, so a diff between two runs shows only real movement.

Use the CLI's --json flag for a row per document (Module, Folder, Kind, Document) when comparing against a checked-in layout.

Do not reach for describe structure here: it groups by document type at every depth and never shows which folder a document sits in.

Moving Documents

The move command relocates existing documents between folders and modules.

Move to a Folder (Same Module)

mdl 1;
move page MyModule.CustomerEdit to folder 'Customer';
move microflow MyModule.ACT_ProcessOrder to folder 'Order';
move snippet MyModule.NavigationMenu to folder 'Shared';
move nanoflow MyModule.NAV_OpenCustomer to folder 'Customer';
move enumeration MyModule.OrderStatus to folder 'Shared';

Move to Module Root (Out of Folder)

mdl 1;
move page MyModule.CustomerEdit to MyModule;

Move Across Modules

mdl 1;
-- Move to another module's root
move page OldModule.CustomerPage to NewModule;

-- Move to a folder in another module
move page OldModule.CustomerPage to folder 'Pages' in NewModule;

Cross-Module Move Warning

Cross-module moves change the qualified name (e.g., OldModule.CustomerPage becomes NewModule.CustomerPage). This breaks by-name references such as:

  • Microflows calling show page OldModule.CustomerPage
  • Other microflows calling call microflow OldModule.SomeMicroflow
  • Widget actions referencing the old qualified name

Always check impact before cross-module moves:

mdl 1;
list impact of OldModule.CustomerPage;
-- Review the output, then move if safe:
move page OldModule.CustomerPage to NewModule;

Folder Rules

  • Folder names are case-sensitive
  • Use / as separator for nested folders: 'Parent/Child/Grandchild'
  • Folders are created automatically if they don't exist
  • Moving to a folder that doesn't exist creates it
  • Empty folders are preserved in the project

Supported Document Types

move accepts every top-level document type, spelled the way describe spells it:

Group Types
Pages page, snippet, building block, layout, menu
Logic microflow, nanoflow, workflow, task queue, scheduled event
Domain enumeration, constant, regular expression
Mappings json structure, import mapping, export mapping
Code java action, javascript action, database connection, data transformer
Resources image collection, icon collection
Integration consumed rest service, published rest service, consumed odata service, published odata service, business event service
AI model, agent, knowledge base, consumed mcp service

move entity is the exception: an entity lives inside a domain model, so it moves between modules only, never into a folder.

If the named document turns out to be a different type, the statement is refused and the error names what it really is — move task queue Mod.JSON_Order reports that Mod.JSON_Order is a json structure.

FOLDER on Create

Every document type takes a folder clause on create, so a document can be placed in the statement that creates it rather than in a separate move. Where the clause goes depends on the statement's shape:

Document Type FOLDER on Create
Page, Snippet folder: 'path' — a property, inside the parentheses
Microflow, Nanoflow folder 'path' — a keyword, before begin
Enumeration, Constant folder 'path' — a keyword, after the definition
Everything else folder 'path' — a keyword, straight after the qualified name
mdl 1;
create import mapping CRM.IMM_Order folder 'Private/Import mappings'
  with json structure CRM.JSON_Order { create CRM.Order { Id = id } };

create task queue CRM.Q_Orders folder 'Private/Queues' ( Parallelism: 3 );

create java action CRM.JA_Sync folder 'Private/Java' () returns string
  as $$return null;$$;

A folder clause on create or modify moves an existing document. It used to be silently ignored: the statement reported success, the folder was created, and the document stayed where it was (#932). Omitting the clause leaves placement alone — it never returns a document to the module root — so adding a folder to a script is safe and removing it is a no-op.

describe emits the clause, so a description replays into the same folder rather than into the module root.

Example: Reorganize a Module

mdl 1;
-- Group all Customer artifacts together
move page CRM.Customer_Overview to folder 'Customer';
move page CRM.Customer_NewEdit to folder 'Customer';
move microflow CRM.ACT_Customer_Save to folder 'Customer';
move microflow CRM.ACT_Customer_Delete to folder 'Customer';
move microflow CRM.ACT_Customer_New to folder 'Customer';
move microflow CRM.VAL_Customer to folder 'Customer';
move snippet CRM.CustomerCard to folder 'Customer';

-- Group all Order artifacts together
move page CRM.Order_Overview to folder 'Order';
move page CRM.Order_NewEdit to folder 'Order';
move microflow CRM.ACT_Order_Save to folder 'Order';
move microflow CRM.ACT_Order_Process to folder 'Order/Processing';

-- Move shared artifacts to a Shared folder or common module
list impact of CRM.Header_Snippet;
move snippet CRM.Header_Snippet to folder 'Shared' in Common;

-- Move entity to different module
list impact of CRM.Customer;
move entity CRM.Customer to CustomerModule;

-- Move enumeration to different module
move enumeration CRM.OrderStatus to SharedModule;

Moving Folders

Use move folder to reorganize folders. Syntax matches document moves: Module.FolderName.

mdl 1;
-- Move a folder into another folder
move folder MyModule.Resources to folder 'Archive';

-- Move a nested folder (use double quotes for paths with /)
move folder MyModule."Orders/Archive" to MyModule;

-- Move a folder to a different module
move folder MyModule.SharedWidgets to CommonModule;

-- Move a folder into a folder in another module
move folder MyModule.Templates to folder 'Shared' in CommonModule;

Deleting Folders

Use drop folder to remove empty folders. The folder must not contain any documents or sub-folders.

mdl 1;
-- Drop an empty folder
drop folder 'OldPages' in MyModule;

-- Drop a nested folder (only the leaf is removed)
drop folder 'Orders/Archive' in MyModule;

-- Move contents out first, then drop
move microflow MyModule.ACT_Process to MyModule;
drop folder 'Processing' in MyModule;

Validation Checklist

  • Folder paths use / separator (not \)
  • FOLDER is a clause after the document name — before BEGIN for microflows, before the (…) properties for pages and snippets; a Folder: property is deprecated (MDL-DEPR105)
  • Cross-module moves: checked impact with list impact of first
  • Folder naming is consistent across modules
  • DROP FOLDER: verify folder is empty before dropping
  • After a batch of moves: list folders in MyModule to confirm the layout