Open Closed

Best approach to add CMS Kit + Public Website to existing ABP solution (multi-tenant) #10326


User avatar
0
abpdevPro created

Hi ABP Support Team,

We have an ABP Commercial project A (our main product) that is already live and running in production.

Now we have a new requirement for a subset of tenants: we want to provide CMS functionality (CMS Kit + Public Website) for those tenants.

To explore this, we created a separate ABP project B using the ABP template with CMS Kit and Public Website enabled, and we’ve already done some customizations in project B.

At this point, we want to bring this CMS capability into our main project A, and we are considering two approaches:

Option 1: Convert project B into a module and integrate it into project A

Make B a reusable module and then include it in A.

Option 2: Install CMS Kit + Public Website into project A directly, and migrate our customizations from project B

We need guidance on:

  1. Which option is the recommended approach for long-term maintainability and upgrade safety (especially since A is already live)?
  2. If option 1 is feasible, what is the recommended way to extract what we built in B (CMS + Public Website customizations) into a proper ABP module and integrate it into A (projects to reference, DependsOn setup, migrations, UI packages, etc.)?
  3. If option 2 is preferred, what is the safest migration path to move the B customizations into A after installing CMS Kit + Public Website (including any typical pitfalls around global features, migrations, and unified admin/public layout configuration)? ​

Our goal is to keep one main solution (A), enable CMS features only where needed, and avoid creating an architecture that becomes difficult to maintain across ABP upgrades.

Thanks in advance for your recommendation and the best-practice steps to implement it.


1 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    1. Which option is better?

    For a long‑lived, upgrade‑friendly Commercial solution, Option 2 is the recommended path:

    • Use your existing, already‑running solution A as the main solution.
    • Install CMS Kit(.Pro) into A and add a Public Website project into A, then
    • Manually merge / move your customizations from B into A.

    This aligns with how ABP team advises adding Public Website/CMS Kit to existing apps:
    you generate a new solution with Public Website, then move that project into your existing solution rather than trying to “convert” another solution into a module.

    From an official support answer:
    “Create a new blank application (that includes public website project) with the same options with your existing application.
    Move the public website project from the newly created solution to your existing solution.”

    (support question: “add public website (and CMS kit) to existing application?”)

    Using a separate “B as a module” works, but:

    • you’ll continually fight template drift and module‑solution mismatches,
    • upgrades are harder (you must track and manually merge ABP template/public-website changes into B‑module forever).

    So, for maintainability and upgrade safety: Option 2.


    1. If you did Option 1: how to convert B into a module and integrate into A?

    This is technically feasible, but more complex/fragile than Option 2.

    High‑level steps if you insist on Option 1:

    1. Refactor B into a proper ABP Application Module
      • Ensure B follows the module layering pattern:
        • B.Domain
        • B.Domain.Shared
        • B.Application
        • B.Application.Contracts
        • B.HttpApi
        • B.HttpApi.Host (optional if you want a separate host)
        • B.Web (for the public website UI)
      • Each should have its own AbpModule class, with proper [DependsOn] attributes, e.g.:
    // B.Domain.Shared
         [DependsOn(
             typeof(AbpDddDomainSharedModule),
             typeof(CmsKitDomainSharedModule) // if you depend on CmsKit
         )]
         public class BDomainSharedModule : AbpModule
         {
         }
    
         // B.Domain
         [DependsOn(
             typeof(AbpDddDomainModule),
             typeof(BDomainSharedModule),
             typeof(CmsKitDomainModule)
         )]
         public class BDomainModule : AbpModule
         {
         }
    
    • Make sure B doesn’t redefine infrastructure that A already has (e.g., EF Core DbContext, identity, SaaS, etc.).
    1. Database & migrations

      • If B currently has its own DbContext & migrations:
        • Decide whether you want:
          • Shared DbContext with A (recommended for a monolith), or
          • Separate schema / connection string.
      • If sharing A’s DbContext:
        • Move B’s entity mappings into A’s DbContext project and regenerate migrations there.
      • If keeping a separate DbContext:
        • Keep B’s B.EntityFrameworkCore with its own migrations & connection string.
    2. Wire the module into A

      • Reference B’s projects from A’s solution (csproj references).
      • In A’s startup module(s), DependsOn the B modules you need, e.g.:
    [DependsOn(
             typeof(BWebModule),
             typeof(CmsKitPublicWebModule) // if used
         )]
         public class AWebModule : AbpModule
         {
         }
    
    1. UI integration

      • If B.Web is a full Public Website (layout, theme, CMS pages):
        • Treat it as A’s Public Website project:
          • Add a project reference from A’s solution.
          • Configure routing, app.UseEndpoints, etc., as in a standard ABP Public Website.
      • Ensure one consistent theme (often LeptonX) and do not duplicate theme modules.
    2. Multi‑tenancy

      • If B contains tenant‑aware components, ensure it uses ABP’s multi‑tenancy as in A (same ICurrentTenant, tenant resolvers, etc.).
      • Use features / settings to control which tenants see the CMS/public website (see section 3.4 below).

    Because this essentially recreates what the ABP “Application Module” template already gives you, and you also must keep up with Public Website template changes, this option is usually not worth the maintenance cost unless you are building a generic module to reuse in multiple, unrelated solutions.


    1. Option 2 in detail: safest way to install CMS Kit + Public Website into A and migrate customizations

    3.1. Add CMS Kit to existing solution A

    1. Install module via CLI (run in A’s solution root):
    # Open-source
       abp add-module Volo.CmsKit --skip-db-migrations
    
       # Commercial (Pro)
       abp add-module Volo.CmsKit.Pro --skip-db-migrations
    
    1. Enable CMS global features in YourProjectNameDomainSharedModule (or GlobalFeatureConfigurator):
    GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit =>
       {
           cmsKit.EnableAll();
       });
    
       GlobalFeatureManager.Instance.Modules.CmsKitPro(cmsKitPro =>
       {
           cmsKitPro.EnableAll();
       });
    
    1. Run EF Core migrations (A’s DbContext project):

      • Add migration including CMS tables.
      • Update DB.

      This is the officially documented install path for CMS Kit into an existing solution.

    3.2. Add a Public Website project into A

    There is no direct “add public website” CLI command to an existing solution. Official guidance:

    1. Create a new temp solution C with the same options as A but with Public Website enabled:
    abp new TempSolution --with-public-website [other-options-matching-A]
    
    1. In solution C, locate the Public Website project (e.g. TempSolution.Public.Web).

    2. Copy that project into A’s solution:

      • Add the project folder under A’s src directory.
      • Add it to A’s .sln.
      • Fix namespaces and project names if needed.
    3. Update references:

      • Ensure A’s Public Website project references:
        • A’s Domain.Shared, Application.Contracts, HttpApi.Client etc., as in C.
        • Volo.CmsKit.Public.Web / Volo.CmsKit.Pro.Public.Web (they should already be referenced from the template).
      • Ensure A’s DbMigrator (if used) knows about the CMS migrations (usually automatic if using the unified DbContext).

    This step gives you a canonical, up‑to‑date Public Website layer, exactly as ABP expects, now living inside solution A.

    3.3. Migrate customizations from B into A

    From your experimental solution B (created with CMS Kit + Public Website):

    1. Identify what you actually changed in B:

      • New/changed pages (Pages/Public/...), view models, components.
      • Theme customizations (styles, partials, layouts).
      • CMS Kit usage: custom menus, widgets, blogs, etc. (often mostly data seeded via UI, not code).
    2. Copy over custom UI code:

      • For page customizations in B.Public.Web:
        • Move them into corresponding folders in A.Public.Web:
          • Pages/Public/...
          • Themes/LeptonX/... overrides
        • Resolve namespace / module differences (A vs B project names).
      • For CMS‑specific views (blogs, dynamic pages, widgets) you extended:
        • Overwrite or extend the relevant Razor Pages in A’s Public Website project.
    3. Copy/merge application/domain logic (if any) from B into A:

      • Application services, DTOs, domain services used by the public website.
      • Add these to A’s Application/Domain projects instead of B’s.
    4. Re‑run and verify migrations if you added new entities for B that need DB tables in A.

    5. Test all flows in A:

      • Admin CMS management (blogs, pages, menus, etc.).
      • Public website display of your custom pages/features.
      • Multi‑tenancy behavior (see 3.4).

    This is conceptually the same as “upgrading imported module source code by re‑downloading and merging” that ABP support often suggests for modules: you bring in a fresh template version and then merge your custom changes on top.

    3.4. Enable CMS/Public Website only for specific tenants

    With everything in a single solution A, you still want only a subset of tenants to have CMS/public web capability.

    Use a combination of:

    1. Feature management / settings per tenant

      • Define a feature (e.g. CmsKit.Enabled) or reuse existing module features.
      • In host UI, enable that feature only for selected tenants.
      • In Public Website project and/or CMS menus, check the feature before showing pages or allowing access.
    2. Tenant‑specific DNS + tenant resolvers

      • Use domain/subdomain‑based tenant resolution so only tenants that have a configured domain actually hit the public website.
      • Tenants without a mapped domain will effectively have no public website.
    3. Permission control

      • Grant CMS admin permissions only to tenants that should manage content.

    This is aligned with ABP’s feature system + multi‑tenancy model and avoids duplicating application code per tenant.


    4. Summary

    • Recommended:

      • Keep A as the only main solution.
      • Install CMS Kit(.Pro) into A.
      • Add a Public Website project to A by generating a temp solution and moving its public‑web project.
      • Merge customizations from B (code only) into A’s projects.
      • Use features + tenant configuration to expose CMS/public web only for selected tenants.
    • Avoid:

      • Treating a full solution (B) as a “module” and embedding it inside A.
        It goes against ABP’s modularity patterns and complicates upgrades significantly.

    Sources

    • CMS Kit module docs (installation, global features, unified/public/admin packages)
      • https://abp.io/docs/latest/modules/cms-kit
    • ABP Modularity basics (module structure, DependsOn, module best practices)
      • https://abp.io/docs/latest/framework/architecture/modularity/basics

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.2.0-preview. Updated on January 20, 2026, 07:04
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.