////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
////

This section covers all the new features introduced in Grails {grailsMajorVersion}

=== Overview

Grails {grailsMajorVersion} is a major release that includes new features, improvements, and dependency upgrades.
This release focuses on enhancing the developer experience, improving performance, and ensuring compatibility with the latest technologies.

For detailed information on how to upgrade to Grails {grailsMajorVersion}, including major dependency changes, please see the xref:upgrading#upgrading80x[Upgrading from Grails 7 to Grails {grailsMajorVersion}] section.
Notable new features are included below.

==== Platform Baseline

Grails {grailsMajorVersion} raises the standard build and runtime baseline to Java 21 and uses Gradle {gradleVersion}.
The standard Grails BOM remains on Groovy {groovyVersion} and Spock {spockVersion}, while Micronaut-enabled Grails applications use Micronaut-specific BOM variants that align with Micronaut 5 and require JDK 25 or later.

==== Spring Boot 4.1 and Spring Framework 7

Grails {grailsMajorVersion} is built on Spring Boot {springBootVersion} and Spring Framework {springVersion}.
This brings the Spring Boot 4 modular artifact layout, Spring Framework 7 API removals, Jackson 3, Tomcat 11 and Jakarta Servlet 6.1, plus Spring Boot 4.1 dependency management for Spring Security 7.1, Spring Data 2026.0 and Micrometer 1.17.

The Grails 8 upgrade guide calls out the major application-impacting changes and links to the Spring Boot 4.0 migration guide, Spring Boot 4.1 release notes and Spring Framework 7.0 release notes.

==== GSP Tag Library Improvements

Grails {grailsMajorVersion} continues the move toward method-based TagLib handlers while preserving compatibility with existing closure-based tags.
Method-defined tags now bind named attributes more predictably, exclude inherited framework and `Object` methods from tag dispatch, and preserve real namespace property getters.

The Grails Gradle extension now defaults `preserveParameterNames` to `true`, so application Groovy compilation preserves method parameter names for features such as typed method TagLib arguments.

Tag library unit tests also clean up and rebuild TagLib metadata automatically between features.
Tests that use `TagLibUnitTest` no longer need to manage `purgeTagLibMetaClass`, and specs that mock additional tag libraries continue to work across feature methods.

==== @GrailsCompileStatic on Controllers That Use Tag Libraries

Controllers annotated with `@GrailsCompileStatic` can now invoke tag library methods without compile-time errors.

Both calling patterns are supported out of the box:

[source,groovy]
----
import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
class BookController {

    def index() {
        // Direct call in the default namespace
        response.writer << link(controller: 'book', action: 'list')

        // Namespaced call via a dispatcher property
        response.writer << my.customTag(attr: 'value')
    }
}
----

`@GrailsCompileStatic` recognises controllers and tag libraries by convention and marks tag dispatch points as permissible dynamic calls, while leaving the rest of the class fully type-checked.

==== Opt All Controllers, Services and Tag Libraries into GrailsCompileStatic

Static compilation can now be enabled for every controller, service and tag library in an application from the nested `compileStatic` block of the `grails` build configuration, without annotating each class:

[source,groovy]
.build.gradle
----
grails {
    compileStatic {
        controllers = true
        services = true
        tagLibs = true
    }
}
----

All three options are disabled by default and independent, or `compileStatic { all = true }` can be used as a shortcut to enable all of them. Any class that declares its own `@CompileDynamic` (or `@GrailsCompileStatic`/`@CompileStatic`/`@GrailsTypeChecked`/`@TypeChecked`) annotation keeps that setting, so the opt-in never overrides an explicit per-class choice. Tag libraries that still declare tags as closure fields (the deprecated form) are skipped automatically by the `tagLibs` opt-in — left dynamically compiled with a build warning — so define tags as methods to opt them in. See the xref:staticTypeCheckingAndCompilation/grailsCompileStatic[GrailsCompileStatic] section for details.

==== Test HTTP Client Form Requests

Integration tests that implement `HttpClientSupport` can now use `httpPostForm(...)` to send `application/x-www-form-urlencoded`
request bodies. The helper URL-encodes form fields using UTF-8, and repeated values in a `Collection` or array are encoded as
repeated keys in insertion order.

==== GORM for MongoDB: TTL, Text, and Reconciled Indexes

GORM for MongoDB can now declare a https://www.mongodb.com/docs/manual/core/index-ttl/[TTL index] directly in the mapping DSL.
Adding `expireAfterSeconds` to the `indexAttributes` of a single date-valued property creates a TTL index, and MongoDB
automatically removes each document once it reaches the configured age:

[source,groovy]
----
class LoginEvent {
    Date dateCreated
    static mapping = {
        dateCreated index: true, indexAttributes: [expireAfterSeconds: 3600]
    }
}
----

A single property can likewise declare a `$text` index — or another special type such as `2dsphere` — through
`indexAttributes: [type: 'text']`.

When the options of an already-created index change between restarts, GORM now reconciles the difference instead of only
logging a conflict. A changed TTL is applied in place with MongoDB's `collMod` command — no drop, no rebuild — while any
other option change is applied by declaring `indexAttributes: [recreateOnConflict: true]`.
