Grails Project Structure and Conventions
Convention over Configuration
Grails' greatest strength is its opinionated structure. Place a file in the right directory and Grails instantly knows its role - no XML wiring, no extra configuration. This lets you focus on business logic instead of framework plumbing.
Standard Directory Layout
grails-app/
controllers/ # request handling
domain/ # GORM model classes
services/ # business logic
views/ # GSP templates
conf/ # configuration
init/ # Application + BootStrap
assets/ # css/js/images
taglib/ # custom tags
src/main/ # Java/Groovy helper classes
src/test/ # Spock tests
build.gradle # build definition
gradle/ # wrapper + propertiescontrollers
Controller class names must end in Controller, and URLs are derived automatically:
grails-app/controllers/com/example/UserController.groovyThe URL mapping for /user is generated for you. Each public method on the controller becomes an action.
domain
Domain classes here map directly to database tables. The class name becomes the table name, and properties become columns. Grails adds the id and version fields automatically.
services
Services are Spring-managed singleton beans that are transactional by default. Keep business logic here and controllers thin.
views
GSP files live here, organized by controller name with a layouts folder for shared page structure and a shared folder for templates.
conf and init
conf holds application configuration (application.yml/application.groovy) plus environment-specific settings. init contains the Application class and BootStrap, which runs setup code at startup.
Why This Structure Matters
- New developers onboard faster because structure is predictable.
- Testing is simpler because roles are clear.
- Refactoring is safe because conventions not magic.
- Deployment is consistent across environments.
Key Points
- Grails is convention-based - location defines role.
- Controllers end in Controller and map to URLs automatically.
- Domain classes become tables; services hold logic.
- Trust the structure; fighting it costs more than it saves.