# roots/bedrock: WordPress with Composer and Git, reviewed for teams that deploy

> 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.

**roots/bedrock** — WordPress boilerplate with Composer and Git, easier configuration, and an improved folder structure

- Repository: https://github.com/roots/bedrock
- Website: https://roots.io/bedrock/
- Stars: 6,576 · Forks: 1,169
- Language: PHP
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/roots-bedrock

## 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.

```bash
cp .env.example .env
```

Open .env and replace the placeholders. The template ships with these keys, among others, and a commented DSN alternative.

```bash
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.

## 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.

## FAQ

### 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.

## Sources

- [License: MIT](https://github.com/roots/bedrock/blob/master/LICENSE)
- [Project website](https://roots.io/bedrock/)
- [README](https://github.com/roots/bedrock/blob/master/README.md)
- [Releases](https://github.com/roots/bedrock/releases)
- [roots/bedrock on GitHub](https://github.com/roots/bedrock)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/roots-bedrock
