BookStack Release v25.11
Dan Brown posted on the 9th of November 2025
Today arrives BookStack v25.11 which makes some significant changes to the database structure, while expanding on API capabilities along with other various improvements.
Upgrade Notices
- Large Database Changes - Significant changes have been made to the database structure. It’s essential you have good backups for your instance before updating, and that you allow extra time for the database to migrate during the update process. On large instances this could be in the range of minutes rather than seconds.
- Caching - The
APP_NAMEenv option is no longer used for the cache key. This option was never documented at all, but if you used this to prevent cache collisions please instead use theCACHE_PREFIXoption.
Database Changes
For every version of BookStack before today, each element of the content hierarchy (Shelves, Books, Chapters and Pages) had their own database table which affords simplicity and ease-of-use for most developer scenarios. This separate table format is not so great when we need to query across different types of items which is very common in BookStack, in areas such as activity lists, book contents, search results, and many other areas. This would result in making extra queries per item type or performing inefficient unions across tables. In some cases, this would present as quirks to the end-user. An example of this is the BookStack search results, which do not have a stable page-count (including via the API) while not being able to sort relevancy across item types and result pages as we’d really like.
In this release the structure has changed significantly, merging the core information of all hierarchy elements into a single table, where they can be indexed & queried as one set of data, while more unique item-specific data is placed into one of two secondary tables.
The results of this are fewer database queries in many areas, leading to a faster and more responsive system. This also allows us to have better search result quality, stability, and paging of search results:

As development goes on we’ll update further areas of the application to make use of this more efficient structure. This approach also has the benefit of fewer database changes and performance implications in the event we add a new hierarchy item in the future.
Ultimately though, apart from proper search paging, this should present no functional difference to end-users or applications/developers using our stable API interfaces, since attention has been paid to ensure those remain stable across this restructuring.
App Time-zones
This release adds a new APP_DISPLAY_TIMEZONE option, which allows you to define a separate
time-zone which will be used for absolute dates shown within the user interface.
This will default to the existing APP_TIMEZONE, but that can now be instead used to define
just the storage time-zone format for date-times in the database.
Generally it’s a good idea to set APP_TIMEZONE to UTC, so it’s stable & standard, then
use APP_DISPLAY_TIMEZONE to configure the time-zone for which most users would be considered within.
As part of these changes, we’ve also gone through all the locations where absolute times are shown in-app, and made their format consistent:

As seen above, display of absolute times will now include a short-hand time-zone indicator so the reader can be sure to understand exactly what time it represents, regardless of if they’re in the same time-zone or not. Further details about these options can be found in our documentation here.
Groovy Code Language Highlighting
This release adds code syntax highlighting support for Groovy, a Java-syntax-compatible object-oriented programming language for the Java platform:

This will show as an option in the WYSIWYG code editor, or can be utilised in the markdown editor by using groovy in the opening code block tag.
New Flags for the “Create Admin” Command
The create admin command has received a couple of new options in this release:
--generate-password: Generate a random password, and echo it back out as the only output on success.--initial: Update the default admin@admin.com user if it exists, otherwise create a new admin user if there’s no existing admin accounts, otherwise do nothing.
These new options provide the components needed to allow automation & scripts to have some control over the initial admin user account in BookStack. This should allow our installation scripts, and any other third-party use/install method, to safely migrate over to having more secure initial accounts rather than globally known default admin credentials. This will be an ongoing change, as I reach-out to other projects to assist in using these more secure approaches, before eventually removing the default user account creation entirely.
API: Docs Navigation Improvements
The API documentation, found at /api/docs within a BookStack instance, has a sidebar
which was becoming quite long with all the endpoints & models being supported over time, making it more difficult to find what’s needed.
In this release, the sidebar has now been organised with the main hierarchy elements (pages, chapters, books and bookshelves) at the start, and everything below that in alphabetical order by model name.
The sidebar also gains a jump-menu, allowing you to quickly find the endpoints for the data model you need.

API: Comments
Comments are now available as part of the BookStack REST API. There’s full create, read, update and delete actions available:

In addition to the comment-specific endpoints, the page-read endpoint will now include all comments for that page, formatted in the same thread-tree style as seen in the UI to prevent extra client-side handling needed to replicate this format.
API: Image Data
We’ve had image API endpoints for a while, but there was a limitation that the actual data could not be
read via the API, outside of exports, leaving images inaccessible in environments
such as those using local_secure_restricted image storage.
To address this, we have a couple of new endpoints:

Both of these endpoints will simply return the image data for the requested image, with one allowing you to look-up image by ID, and the other by URL; the latter added as a convenience helper for direct data fetching based on image links within content.
Translations
It wouldn’t be a feature release without a load of translation updates! A big thanks again to all the meticulous multilingual marvels of language below who have helped translate BookStack since our last feature release:
- Silvia Isern (eiendragon) - Catalan - 996 words
- Tim (thegatesdev) - Dutch - 172 words
- ahmad abbaspour (deshneh.dar.diss) - Persian - 148 words
- Dennis Kron Pedersen (ahjdp) - Danish - 145 words
- João Faro (FaroJoaoFaro) - Portuguese - 114 words
- Jeff Huang (s8321414) - Chinese Traditional - 107 words
- CellCat - Chinese Simplified - 77 words
- iamwhoiamwhoami - Swedish - 70 words
- toras9000 - Japanese - 55 words
- Vitaliy (gviabcua) - Ukrainian - 46 words
- Grogui - French - 32 words
- Ngoc Lan Phung (lanpncz) - Vietnamese - 32 words
- m0uch0 - Spanish - 31 words
- scureza - Italian - 22 words
- ltnzr - French - 17 words
- cbridi - Portuguese, Brazilian - 16 words
- MrCharlesIII - Arabic - 16 words
- Indrek Haav (IndrekHaav) - Estonian - 14 words
- David Olsen (dawin) - Danish - 13 words
- HrCalmar - Danish - 11 words
- Honza Nagy (honza.nagy) - Czech - 11 words
- M Nafis Al Mukhdi (mnafisalmukhdi1) - Indonesian - 9 words
- Danilo dos Santos Barbosa (bozochegou) - Portuguese, Brazilian - 7 words
- Frank Holler (holler.frank) - German; German Informal - 6 words
- mabdullah - Arabic - 5 words
- Worive - French; Catalan - 4 words
- Chris (furesoft) - German - 3 words
Word counts are those tracked by Crowdin, indicating original EN words translated.
Codebase Updates
In this release we upgraded the core framework used from Laravel 11 to Laravel 12. This was done much earlier than usual, mostly thanks to being a minor upgrade which does not impose PHP minimum version changes and therefore doesn’t impact BookStack’s requirements.
Along with this, other codebase changes have been made such as:
- Upgrading our static code analysis to be more strict, and address a range of existing lack of typing.
- Upgraded BookStack’s PHP dependencies across major versions where needed.
- Updated permission checks to use enums instead of strings to avoid string-based-errors.
- Removed some redundant columns from the database, and added better clean-up & nullification of old IDs.
Next Steps
Since this release was so heavy on large back-end changes, I’d like the next one to be a lighter release of little improvements which hopefully I can provide as a bit of a Christmas present for the end of December. One of these improvements will be focused on building a more robust and focused slug/URL tracking solution to further assist URL change resolution.
Since it was skipped for this release cycle due to time, I’ll also look to include an initial developer API implementation for our new WYSIWYG editor.
Full List of Changes
Released in v25.11
- Added API endpoints for comments. (#5850, #4194))
- Added API endpoints for reading image data. (#5860, #5519)
- Added Groovy code syntax highlighting support. (#5822)
- Added new flags to the create admin command. (#5749)
- Added option for display timezone, and improved UI use consistency. (#5790, #4786)
- Added proper pagination to search. (#5854)
- Updated API docs with better model ordering, and quick navigation select. (#5865)
- Updated codebase to meet PHPstan level 3. (#5785)
- Updated database comments table to remove redundant text column. (#4821)
- Updated database format for core item types. (#5800)
- Updated framework to Laravel 12, and perform some major dependency upgrades. (#5782)
- Updated page delete handling to nullify related images instead of leaving old IDs. (#5846)
- Updated permission handling in code to use enums instead of strings. (#5793)
- Updated translations with latest Crowdin changes. (#5843)
- Updated user delete handling to nullify, or better handle, ID references on delete. (#5844)
- Fixed old API-scripts link leading to archived repo. (#5813)
- Fixed search timeout when a high per-page frequency match was encountered. (#5863)
Released in v25.07.3
- Updated translations with latest Crowdin changes. (#5786)
- Updated PHP package versions.
- Fixed PWA manifest access when behind authenticated proxies. Thanks to @tfnh621. (#5820)
Released in v25.07.2
- Updated new WYSIWYG editor with various fixes focused on collapsible block behaviour & interaction. (#5775)
- Updated translations with latest Crowdin changes. (#5759)
- Updated versions of PHP dependencies.
- Updated code to address some remaining PHP 8.4 deprecations.
- Fixed diagrams in ZIP imports not being editable post-import. (#5761)
- Fixed books detaching from shelves on shelf update where users don’t have permission to view child books. (#5728)
Released in v25.07.1
- Updated translations with latest Crowdin changes. (#5740)
- Updated PHP package versions.
- Fixed open redirect with stricter location checking.
- Fixed users being logged out on ZIP import errors. (#5754)
- Fixed menu accessibility tagging. (#5753, #5752)
- Fixed scenarios where MAIL_PORT could interfere with tests. (#5755)
Header Image Credits: Photo by David Gubler (CC-BY-SA-4) - Image Modified