roots/bedrock: WordPress with Composer and Git, reviewed for teams that deploy
WordPress boilerplate with Composer and Git, easier configuration, and an improved folder structure
At a glance
- What is it?
- Bedrock is a WordPress boilerplate that moves core, plugins and themes into Composer and pushes configuration into environment files. It suits developers who already deploy with Git. It is a poor fit for anyone who wants the standard wp-admin updater.
- Who is it for?
- Adopt roots/bedrock if your team already deploys WordPress through Git and wants plugin and core versions recorded in composer.json rather than clicked into wp-admin. Do not adopt it if you rely on the built-in updater, on FTP uploads, or on a host that hardcodes the standard WordPress layout.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What roots/bedrock changes about a WordPress install
A stock WordPress site treats code as something you upload and configuration as something you edit in a browser. Bedrock inverts both. The README describes the project as a "WordPress boilerplate for developers that want to manage their projects with Git and Composer", and much of its philosophy comes from the Twelve-Factor App methodology, including the WordPress-specific version linked from the README.
The audience is narrow and specific: developers running client sites, agencies with repeatable builds, and teams that already review code in pull requests. If nobody on the team has used Composer, Bedrock adds a dependency-management layer before it removes any work. The payoff shows up later, when a plugin update has to be traced, reverted, or reproduced on a staging site.
The repository layout tells the story before any documentation does. There is a composer.json at the root, a config/ directory, a web/ directory, and a .env.example file. In a conventional WordPress install those four things would be a wp-config.php, a wp-content folder, and a database dump nobody can diff.
The mechanism: Composer for code, .env for configuration, web/ for the docroot
Three moving parts do the work.
Composer manages code. The README lists a roots/wordpress package for WordPress core and points at the WP Packages repository for plugins and themes. That means WordPress itself is a dependency with a version constraint, not a tarball you unpack. The recent releases follow WordPress closely: 1.31.5 ships with WordPress 7.1.1, 1.31.4 with 7.1, and 1.31.3 with 7.0.4. Each Bedrock tag is effectively a statement about which core version the boilerplate was prepared for.
Dotenv manages configuration. The .env.example file holds database credentials, WordPress salts, and site URLs. The README calls this "easy WordPress configuration with environment specific files", and the mechanism is the vlucas/phpdotenv library. Because the values live outside the repository, the same commit can run against a local database and a production one.
The web/ directory becomes the document root. Only public files sit there, which is the structural change most likely to break an existing host. Everything else (composer.json, config/, the .env file) lives above the docroot where a misconfigured server cannot serve it.
One detail worth noting: the README mentions an autoloader for mu-plugins, letting regular plugins load as must-use plugins. That is the kind of feature that only matters once you have plugins you want to force-activate everywhere, but it is a real difference from stock WordPress.
Installing roots/bedrock and setting up the first environment
The README does not inline installation steps. It says to see the Bedrock installation documentation at roots.io/bedrock/docs/installation/, so treat that page as the authority rather than anything below.
The repository is a Composer package named roots/bedrock, so the conventional entry point is a create-project command run in the parent directory of where the site should live. Composer pulls the boilerplate and its dependencies, including the roots/wordpress core package, and the result is the layout visible in the repository: composer.json, config/, web/, and .env.example.
Next, copy the example environment file. The shipped file defines the database variables first, then the site variables.
cp .env.example .envOpen .env and replace the placeholders. The template ships with these keys, among others, and a commented DSN alternative.
DB_NAME='database_name'
DB_USER='database_user'
DB_PASSWORD='database_password'
WP_ENV='development'
WP_HOME='http://example.com'
WP_SITEURL="${WP_HOME}/wp"Note that WP_SITEURL is built from WP_HOME rather than typed twice, and that the example points the site URL at a /wp path. The salts are placeholders reading 'generateme'; the file points at https://roots.io/salts.html to generate real ones. Leaving those unchanged on a public site is a mistake, not a shortcut.
The file also documents optional variables. DB_HOST is commented out, with a note that 127.0.0.1 helps when you hit mysqli 2002 or socket connection issues. DB_PREFIX defaults to wp_, and WP_DEBUG_LOG can take an explicit path. There is a wp-cli.yml at the repository root, which suggests WP-CLI is expected in the workflow, though the README does not describe it.
Where roots/bedrock gets in the way
The strongest argument against Bedrock is that it fights the WordPress admin. Plugin and theme installation through wp-admin assumes WordPress can write to its own directories. Under Composer, that assumption is wrong: the filesystem is a build artifact, and a plugin installed through the dashboard will be absent from composer.json, absent from the lock file, and gone the next time someone rebuilds the site. Teams that adopt Bedrock have to accept that the wp-admin installer becomes a trap rather than a feature.
Hosting is the second constraint. The web/ docroot is not the WordPress default, and shared hosts that assume WordPress lives at the domain root need configuration or a different plan. The README does not document a fallback for hosts that cannot move the docroot, and it does not document rollback either.
Configuration errors are also quieter than they look. A missing or malformed .env file produces a site that cannot connect to its database, and the variables are read at runtime rather than validated at build time. Nothing in the repository checks that the salts are real or that WP_HOME matches the actual domain.
Finally, the release cadence ties Bedrock to WordPress core releases. Releases 1.31.3 through 1.31.5 landed between 2026-08-12 and 2026-09-17, tracking WordPress 7.0.4, 7.1 and 7.1.1. For a team that wants to pin WordPress and upgrade on its own schedule, that coupling is friction. The last push to the repository was on 2026-09-21.
Bedrock against a plain Composer-managed WordPress
The obvious alternative is not another boilerplate but the manual version of the same idea: keep a stock WordPress install, add a composer.json, and require a core package alongside your plugins. That approach gets you dependency management without changing the folder structure or the configuration model, and it keeps wp-admin's installer working.
The difference is where the conventions come from. With a hand-rolled setup, the docroot, the config strategy and the mu-plugin autoloader are decisions you make and document yourself. Bedrock ships those decisions already made: config/ for environment files, web/ for public files, Dotenv for secrets, roots/wordpress for core, and WP Packages as the plugin and theme source. You trade flexibility for a layout that other Bedrock users will recognise immediately.
That trade is the whole point. A hand-rolled composer.json on top of stock WordPress is easier to adopt incrementally, and easier to abandon. Bedrock is a commitment to a specific structure, and moving a live site back out of it is not something the README covers.
Maintenance, licensing and what to check before adopting
Bedrock is MIT licensed, which is permissive and imposes no obligation on how you deploy the result. The licence covers the boilerplate; WordPress core is distributed under its own terms, and the plugins you pull through WP Packages carry their own licences. That mix is worth reviewing per project rather than assuming the MIT label applies to everything in the vendor directory. This is a factual note about the licence identifier, not legal advice.
Upgrade cost has two layers. The Bedrock layer moves when the project tags a release, and the recent tags show that happening roughly in step with WordPress point releases. The application layer moves when you run Composer, which is also when you find out whether a plugin's latest version is compatible with the core version you pinned. Bedrock makes that visible in a diff; it does not make it painless.
The repository carries tests/ and phpunit.xml.dist, plus pint.json for code style and a .devcontainer/ directory, so there is a defined development setup and a test suite for the boilerplate itself. Those test the boilerplate, not your site. The README does not describe a migration path from an existing WordPress install, so plan that work separately.
Editorial conclusion
Adopt roots/bedrock if your team already deploys WordPress through Git and wants plugin and core versions recorded in composer.json rather than clicked into wp-admin. Do not adopt it if you rely on the built-in updater, on FTP uploads, or on a host that hardcodes the standard WordPress layout. Before committing, verify three things in the repository: that the config/ directory matches the environment variables you actually set, that web/ is the docroot your host expects, and that the WordPress version pinned by the roots/wordpress package is one your plugins support.
Frequently asked questions
How do I install roots/bedrock?
The README points to the Bedrock installation documentation at roots.io/bedrock/docs/installation/ rather than listing steps inline. The package is published as roots/bedrock on Packagist, and the repository ships a .env.example file you copy to .env and fill in with database credentials and salts.
Does roots/bedrock replace wp-config.php with environment variables?
Yes. The README describes easy WordPress configuration with environment specific files and environment variables handled by Dotenv, and the .env.example file carries DB_NAME, DB_USER, DB_PASSWORD, WP_ENV, WP_HOME and the eight WordPress salt keys.
What is the web/ directory in roots/bedrock used for?
It is the document root. The repository keeps composer.json, config/ and the environment file outside it, so only public files sit under web/. The README lists an improved folder structure as one of the project's main changes.
Can I still install plugins from the WordPress admin in roots/bedrock?
The project manages plugins and themes through Composer, using the WP Packages repository according to the README. The README does not document the wp-admin installer as a supported path, and a plugin installed that way would not appear in composer.json.
What licence does roots/bedrock use?
The repository is MIT licensed, as stated in the LICENSE.md file. That covers the boilerplate itself; WordPress core and any plugins you pull in carry their own licences.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/roots-bedrock)