Modernizing IndieCommerce: An E-Commerce Platform for Independent Bookstores
Rebuilding a Nonprofit's Shared Storefront Platform on Drupal
How a Lullabot team, including Eduardo Telaya as a senior developer, modernized the American Booksellers Association's IndieCommerce platform on Drupal — faster store onboarding, automated testing, and PCI compliance.
Executive Summary
The American Booksellers Association (ABA) is a nonprofit trade association representing independent bookstores across the United States. For years, its members relied on IndieCommerce, a shared e-commerce platform that let small, independently owned bookstores compete online against much larger retailers without each store building its own storefront from scratch.
That original platform, IndieCommerce 1.0, was not a niche project. According to Lullabot’s public case study, it had processed more than $110 million in sales across 23 million unique visitors. A platform operating at that scale for years inevitably accumulates technical debt, aging infrastructure assumptions, and operational friction that becomes harder to justify as the surrounding web ecosystem moves on.
The ABA engaged Lullabot to build IndieCommerce 2.0: a modernized, Drupal-based e-commerce platform intended as a credible alternative to commercial options like Shopify or BigCommerce, but purpose-built for the needs and economics of independent bookstores. I joined this effort as one of the senior developers on a team that, per Lullabot’s published credits, included roughly ten contributors spanning engineering, design, project management, and technical leadership.
This is a team case study, not a solo one. I am describing the platform we built together, the kind of engineering problems a project like this presents, and the parts of that problem space a senior developer on the team would have been expected to reason about — without claiming individual authorship of decisions the public record attributes to the team as a whole.
The Platform Being Modernized
Independent bookstores operate on different economics than national chains. Most don’t have in-house engineering teams, dedicated DevOps staff, or budget for a custom storefront build. IndieCommerce existed specifically to close that gap: a shared platform where a single engineering investment could serve hundreds of independent stores, each with its own catalog, branding, and local identity, without each store bearing the full cost of building and operating its own e-commerce stack.
That shared-platform model is powerful, but it is also architecturally demanding in a specific way. A platform serving many independent, non-technical operators has to solve problems that a single-tenant storefront doesn’t:
- Store setup and onboarding has to be fast enough that a bookstore owner without engineering support can get a working storefront live.
- Catalog data — potentially millions of book records — has to be shared or easily reusable across stores rather than manually entered per store.
- Deployment and change management has to be safe at the platform level, because a regression doesn’t just affect one store, it affects the shared infrastructure every store depends on.
- Payment handling has to meet PCI compliance requirements across every store on the platform, not just the platform operator’s own transactions.
- Performance and accessibility expectations have risen since the original platform launched, and a multi-tenant architecture makes uniform improvement harder than it would be on a single site.
IndieCommerce 1.0 had answered those questions once, years earlier, under different constraints. IndieCommerce 2.0 had to answer them again, on Drupal, in a way that could keep serving a nonprofit’s membership for years without requiring ABA to take on a commercial platform’s licensing costs or lock-in.
Architecture Overview
At a high level, the modernized platform followed a pattern familiar to anyone who has built multi-tenant systems on Drupal: a shared codebase and shared infrastructure, with per-store configuration and content providing the differentiation that makes each bookstore’s site feel like its own, rather than a reskinned template.
| Layer | Responsibility |
|---|---|
| Shared Drupal platform | Core commerce logic, catalog data model, checkout flow, payment integration, shared modules |
| Per-store configuration | Branding, store-specific catalog curation, local content, storefront customization |
| Shared book database integration | Catalog enrichment from ABA’s book data source, reducing manual per-store data entry |
| DevOps / CI pipeline | Automated testing and deployment shared across every store on the platform |
| Compliance layer | PCI-compliant payment handling applied consistently across all stores |
The public case study doesn’t publish the platform’s internal module boundaries or infrastructure diagrams, so I’m not going to invent ones here. What I can describe honestly is the shape of the problem: build one well-tested, well-governed platform, and let configuration — not code forks — be the mechanism that makes hundreds of independently branded stores possible. That’s the same architectural instinct behind most durable multi-tenant commerce and content platforms, and it’s consistent with the outcomes the public case study reports: faster onboarding, centralized testing, and platform-wide compliance. Engineering Approach Note Hundreds of independent bookstores needed their own storefronts, but ABA — a nonprofit — could not sustain the cost of maintaining hundreds of independent codebases. A shared platform was the only economically viable path, but it concentrates risk: any defect in shared code is a defect for every store at once. A multi-tenant architecture on a shared Drupal codebase, where differentiation between stores lives in configuration and content rather than in forked code. This is the standard pattern a senior Drupal team reaches for in this situation, because it keeps the platform upgradeable as a single unit rather than as hundreds of diverging installations. A shared platform demands much stronger testing and release discipline than a single-tenant site would, since a bad deploy has blast radius across every store. It also demands more careful configuration governance, so that "customization" doesn't quietly turn into "fork."AN-001 — Shared Platform vs. Independent Storefronts
Context
The Approach
Tradeoffs
Cutting Onboarding From Months to Weeks
According to Lullabot’s case study, one of the most concrete outcomes of the rebuild was a dramatic reduction in how long it took to bring a new store onto the platform — from a couple of months down to a couple of weeks.
That kind of improvement rarely comes from a single change. It is usually the compounding effect of several things happening at once: a clearer store-provisioning process, better default configuration so new stores start from a sane baseline instead of a blank slate, less manual, error-prone setup work, and a platform stable enough that provisioning a new store doesn’t require bespoke engineering attention each time.
For a nonprofit serving a membership of small businesses, onboarding time isn’t just an engineering metric. It’s the difference between a bookstore owner being able to get online quickly, during whatever seasonal or competitive window matters to their business, and losing momentum waiting on a manual setup process. Reducing that onboarding window from months to weeks measurably expanded what the platform could do for its members without a corresponding increase in engineering headcount per store.
Automated Testing as a Deployment Safety Net
Per the public case study, the team introduced automated testing specifically to reduce deployment errors. On a shared, multi-tenant platform, this is less of a nice-to-have and more of a structural requirement.
When one codebase serves hundreds of independently operated storefronts, the cost of a regression scales with the number of stores affected, not with the size of the change that caused it. A small, well-intentioned fix for one store’s edge case can break checkout for every other store on the platform if it isn’t caught before release. That asymmetry — small change, platform-wide blast radius — is exactly the situation automated testing exists to guard against. Engineering Approach Note A shared commerce platform means every deployment is, in effect, a deployment to every store at once. Manual QA doesn't scale well against that risk surface, especially for a small nonprofit-facing engineering team that can't manually regression-test hundreds of storefronts before every release. Build automated test coverage around the shared commerce flows — catalog, cart, checkout, payment — that every store depends on, so regressions in shared logic are caught before deployment rather than discovered by a bookstore owner's customers. Automated testing requires upfront investment and ongoing maintenance as the platform evolves. For a platform at this scale, that investment pays for itself the first time it catches a regression that would otherwise have affected every store simultaneously.AN-002 — Automated Testing as a Deployment Safety Net
Context
The Approach
Tradeoffs
Integrating Millions of Books
The public case study highlights integrated access to millions of books through ABA’s book database as one of the platform’s capabilities. For independent bookstores, this matters enormously: a small bookstore cannot realistically maintain a catalog of millions of titles by hand, with accurate metadata, cover art, and availability information kept current. Engineering Approach Note Every independent bookstore on the platform needed a usable, searchable catalog, but none of them could realistically maintain book metadata at the scale of a national retailer's catalog on their own. Integrate the storefront platform with ABA's existing book database so that catalog data — titles, metadata, and availability — is sourced centrally and made available to every store, rather than re-entered independently by each one. This is the same general shape as any catalog-enrichment integration: treat the shared data source as the system of record for product data, and let individual stores curate and present a subset of it rather than maintain their own copy. Centralizing catalog data reduces duplication and manual effort, but it also means the integration layer between Drupal and the book database becomes a critical dependency that the whole platform's product experience rests on.AN-003 — Catalog Integration at Bookstore Scale
Context
The Approach
Tradeoffs
Reaching PCI Compliance
Payment Card Industry (PCI) compliance is a non-negotiable requirement for any platform processing card payments, and it becomes considerably more involved on a shared, multi-tenant platform than it would be on a single storefront. Per Lullabot’s case study, the rebuilt platform achieved full PCI compliance. Engineering Approach Note A multi-tenant e-commerce platform has to meet PCI requirements consistently across every store it hosts. A compliance gap in shared payment-handling code is a gap for every store simultaneously, not an isolated incident. Centralize payment handling in the shared platform layer rather than letting individual stores implement their own checkout or card-handling logic, so compliance work is done once, verified once, and inherited by every store rather than re-solved per storefront. Centralizing payment handling reduces per-store flexibility around checkout customization, but it is the only practical way to keep compliance scope manageable across hundreds of independently operated stores.AN-004 — PCI Compliance Across a Shared Platform
Context
The Approach
Tradeoffs
Performance and Accessibility
The public case study also credits the rebuild with improved performance and accessibility. These are the kinds of improvements that rarely trace back to one dramatic change — more often, they come from a long list of smaller ones: faster page rendering, better caching strategy, semantic markup, keyboard navigation, color contrast, and the general discipline of treating non-functional requirements as first-class work rather than an afterthought bolted on at the end of a project.
For a platform serving independent bookstores and their customers, accessibility is not a compliance checkbox. It directly affects whether a bookstore’s online storefront is usable by the full range of people who might want to buy a book from it — which is, after all, the entire point of the platform existing.
Working as Part of a Ten-Person Team
Per Lullabot’s public case study, the project credited roughly ten named contributors: Adam Varn, Cristina Chumillas, Matt Kleve, Pauline Judge, Sally Young, Ezequiel Vázquez, Andrew Berry (VP of Technology), Albert Hughes (Technical Project Manager), Pablo López Escobés, Megh Plunkett, and myself as a Senior Developer.
I’m naming the team here deliberately, rather than writing this case study as if the architecture and outcomes were mine alone. A platform like IndieCommerce 2.0 — spanning commerce logic, catalog integration, DevOps automation, compliance, performance, and accessibility — is the product of a cross-functional team working over an extended engagement, not one engineer’s individual output. My role, as one of the senior developers on that team, was to contribute to that shared effort; the public record doesn’t break out which specific pieces I personally built, and I’m not going to invent that level of specificity here. What I can speak to honestly is the kind of problems a senior Drupal developer on a team like this would be expected to help solve, which is what the approach notes above describe.
Lessons Learned
A few things stand out, looking back at this kind of project in general terms.
Multi-tenant platforms succeed or fail on governance as much as on code. The technical pattern — shared codebase, per-tenant configuration — is well understood. What makes it work in practice is discipline about what belongs in configuration versus what quietly becomes a fork.
Nonprofit-serving platforms have real economic constraints that shape architecture. A shared platform exists because hundreds of small, independent businesses couldn’t each justify their own engineering investment. That constraint isn’t incidental to the architecture — it’s the reason the architecture looks the way it does.
Deployment safety matters more as blast radius grows. Automated testing on a single-tenant site is good practice. On a platform where every deployment reaches every tenant simultaneously, it becomes closer to a requirement.
Compliance and catalog integrations are infrastructure, not features. Both PCI compliance and the book database integration described above function as foundational infrastructure that every store depends on, even though neither is something an end user directly interacts with as a “feature.”
Approach Notes Summary
| Note | Topic | Nature |
|---|---|---|
| AN-001 | Shared platform vs. independent storefronts | Reconstructed approach |
| AN-002 | Automated testing as a deployment safety net | Reconstructed approach |
| AN-003 | Catalog integration at bookstore scale | Reconstructed approach |
| AN-004 | PCI compliance across a shared platform | Reconstructed approach |
These notes describe the shape of the engineering problem and the pattern a senior developer on this team would reasonably have applied — not a documented internal decision log. The outcomes they’re grounded in (faster onboarding, reduced deployment errors, catalog integration, PCI compliance, improved performance and accessibility) are drawn directly from Lullabot’s public case study.
Final Thoughts
IndieCommerce 2.0 is a good example of a project where the hardest engineering problems aren’t algorithmic — they’re structural. How do you let hundreds of independent businesses each feel like they have their own storefront, while keeping one platform maintainable, testable, compliant, and fast enough to serve all of them well? That’s the problem a nonprofit trade association and a cross-functional engineering team solved together, and it’s the problem I contributed to as one of the senior developers on that team during my time at Lullabot.
Explore all Engineering Case Studies or read ECS-004: Migrating Universal Kids From Drupal 7 to Drupal 8.