Groovy Server Pages (GSP) gives Grails developers a structured, convention-driven way to build dynamic web interfaces without duplicating markup. Whether you're managing a multi-controller application or building a shared component library,
Groovy Server Pages template and layout systems handle the heavy lifting, keeping your views modular, consistent, and maintainable.
Understanding GSP TemplatesTemplates are partial view fragments. Grails identifies them by a leading underscore in the filename (e.g., _bookTemplate.gsp). They live in grails-app/views/controllerName/ for controller-specific use, or in a shared path like grails-app/views/shared/ for application-wide reuse.
Rendering a template in a view:<g:render template="bookTemplate" model="[book: myBook]" />
Rendering over a collection:<g:render template="bookTemplate" var="book" collection="${bookList}" />
Shorthand using the tmpl namespace:<tmpl:bookTemplate book="${myBook}" />
This is equivalent to the g:render call above, just cleaner syntax.
Controllers can also render templates directly and write to the response:
render(template: "bookTemplate", model: [book: b])
To capture the output as a String instead:
String content = g.render(template: "bookTemplate", model: [book: b])
Implementing Layouts with SitemeshGrails uses
Sitemesh as its decorator engine. Layouts sit in grails-app/views/layouts/ and wrap individual views with shared structure, navigation, headers, and footers.
A minimal layout file:<html>
<head>
<title><g:layoutTitle default="My App" /></title>
<g:layoutHead />
</head>
<body>
<div class="menu"><!-- shared nav --></div>
<div class="body"><g:layoutBody /></div>
</body>
</html>
Three ways to assign a layout:1. Meta tag in the view: <meta name="layout" content="main" />
2. Controller-level declaration: static layout = 'customer'
3. Layout by convention: a file named grails-app/views/layouts/book.gsp auto-applies to all BookController views; book/list.gsp applies only to the list action
If no layout is matched, Grails falls back to grails-app/views/layouts/application.gsp. You can override this default in application.yml:
grails.sitemesh.default.layout: myLayoutName
For granular control, Sitemesh
content blocks let you partition a page into named regions:
<content tag="header">...</content>
<content tag="body">...</content>
Each region can then receive its own sub-layout using <g:applyLayout> inside the main layout file.
Performance Optimization and Warmup Cache RequestsAfter a deployment or cache purge, a
warmup cache request preloads data and compiled view state so your application responds at full speed from the first real user hit, rather than absorbing cold-start latency on live traffic.
For GSP-specific tuning, Grails provides reload controls you can set in application.yml or as system properties:
grails.gsp.enable.reloadDefault: false
Purpose: Reloads modified GSPs at runtime
grails.gsp.reload.interval
Default: 5000 ms
Purpose: Interval between file modification checks
grails.gsp.reload.granularityDefault: 1000 ms
Purpose: Leeway for out-of-date file detection
grails.resources.cachePeriodDefault: not set
Purpose: Sets Cache-Control: max-age (in seconds) for static assets
Keep reload
disabled in production. Frequent recompilation consumes permgen space and can force a server restart under heavy change loads.
GSP Templates vs. Layouts: A Direct ComparisonPrimary useGSP Templates: Reusable UI fragments
GSP Layouts (Sitemesh): Full-page decoration
File locationGSP Templates: grails-app/views/controllerName/ or shared path
GSP Layouts (Sitemesh): grails-app/views/layouts/
Naming conventionGSP Templates: Underscore prefix (_name.gsp)
GSP Layouts (Sitemesh): Standard name (main.gsp)
Triggered byGSP Templates: g:render, tmpl:, or render() in controller
GSP Layouts (Sitemesh): Meta tag, static layout, or convention
Model passingGSP Templates: model map or var/collection attributes
GSP Layouts (Sitemesh): pageProperty, g:layoutBody
Nesting supportGSP Templates: Via g:applyLayout on included templates
GSP Layouts (Sitemesh): Yes, layouts can nest layouts
Best forGSP Templates: Cards, tables, form fields, list items
GSP Layouts (Sitemesh): App shell, nav, header, footer
Best Practices for Clean Code➥Name templates clearly. _userCard.gsp beats _partial1.gsp.
➥Use absolute paths for shared templates (e.g., <g:render template="/shared/alert" />) to avoid path ambiguity across controllers.
➥Pass only what the template needs. Lean model maps make templates easier to test and reuse.
➥Disable Fields Plugin template caching during development with grails.plugin.fields.disableLookupCache: true, re-enable it before going to production.
➥Organize layouts by subdirectory when you have multiple layout variants: static layout = 'custom/customer' maps to grails-app/views/layouts/custom/customer.gsp.
Keep Your Views Working For YouModular GSP development pays dividends over time. Templates reduce duplication at the component level; layouts enforce structural consistency across the entire app. Together, they let your team move fast without breaking visual coherence.
The next step: audit your current views for repeated markup, extract it into a named template, and hook it into a shared layout. Small refactors now prevent large maintenance headaches later.
FAQs1. What's the difference between g:render and g:include in Grails GSP?g:render renders a GSP template fragment within the current response. g:include makes a full server-side sub-request to a controller action and embeds the result—useful when you need controller logic to run, but heavier than a simple template render.
2. Can a Grails layout apply a nested layout?Yes. You can apply one layout inside another using <g:applyLayout name="outerLayout"> within a layout file. Sitemesh content blocks let each nested region get its own decorator.
3. Why does my template change not appear after I update the file?In production mode, GSP reloading is off by default. Set grails.gsp.enable.reload: true in application.yml to pick up changes at runtime—but be aware this increases memory usage over time.
4. How do I share a template across multiple controllers?Place the template in grails-app/views/shared/_myTemplate.gsp and reference it with an absolute path: <g:render template="/shared/myTemplate" />.
5. When should I use a tag library instead of a GSP template?Reach for a tag library (in grails-app/taglib) when you need programmatic logic, conditional rendering, iteration with injected variables, or access to request/session scope. Pure markup with minimal logic belongs in a GSP template.