TDS Classic exposes three deployment-related settings that, together, decide what every item in a TDS project looks like in the target Sitecore database after a deploy. Most teams set them once during project setup and then get bitten years later when a deploy unexpectedly recycles half the templates tree, or a "deletion" never reaches the web database. This post walks through what each setting actually does, how they interact, what happens with the master and web databases, and the combinations to watch.
Scope: TDS Classic 6.x on Sitecore 10.x. Behavior described here also applies to late TDS 5.x.
The three dimensions
| Dimension | Scope | What it controls |
|---|---|---|
| Item Deployment | Per item | Whether the item itself is created, overwritten, or skipped |
| Child Item Synchronization (CIS) | Per item | Whether TDS treats descendants of the item as TDS-managed |
| Recursive Deploy Action (RDA) | Per project build configuration | What TDS does with descendants in Sitecore that are not in the project |
They operate on different axes. Item Deployment governs the item itself. CIS plus RDA govern strays (items in Sitecore but not in the project). They never overlap.
1. Item Deployment
Item Deployment is a per-item property that controls how TDS treats the item itself during a deployment. It does not affect siblings or descendants, only the deserialization of this specific item into the target database. The property is set in the item's Visual Studio Properties window, or in bulk via the right-click Deployment Property Manager. The value is captured in the per-deploy DeployedItems.xml manifest that the TDS post-deploy processor reads at install time. Field-Level Deployment is an override on top of Item Deployment, allowing specific fields (e.g. __Renderings, __Security) to be force-deployed even on DeployOnce items.
Options:
- DeployOnce ("Once"). Item is created if missing in the target. If already present, TDS leaves it alone with no field overwrite. Use for items that ship once and are then owned by the target environment, such as initial content stubs and default settings rows that may diverge per environment.
- AlwaysUpdate ("Always"). Item is created if missing, fully overwritten if present. Every serialized field is reset to the project's value on every deploy. Use for developer-owned items that must be authoritative in every environment: templates, renderings, layouts, branches, sublayouts.
- Placeholder ("Never"). Item exists in the project for organizational purposes but is never written to the manifest, never deployed, never synced. Use for structural ancestors you want to keep in the project tree but not touch in any environment, such as
/sitecore/templatesand/sitecore/media libraryroots. Available since TDS Classic 5.8 (March 2019).
Note: Sitecore's package installer force-overwrites __Standard Values items regardless of the TDS setting. Surface this with the Prevent Deploy Once Standard Values validator.
2. Child Item Synchronization (CIS)
CIS is a per-item property that scopes which descendants TDS considers part of this project's responsibility. It does two distinct jobs: during the Sync Window it controls how deep the bidirectional comparison walks, and during deployment it controls whether the post-deploy processor walks this item's children in the target database to look for strays. CIS is the gate for RDA: if CIS is None on a parent, no pruning occurs under that parent regardless of the RDA value. CIS is evaluated per item by the post-deploy step, it is not inherited at runtime.
Options:
- NoChildSynchronization ("None", default). TDS does not walk this item's children at deploy time. Strays under this item are never pruned, even if RDA is Delete or Recycle.
- KeepDirectDescendantsSynchronized ("KeepDirect"). TDS walks one level below this item. Strays at the immediate child level are subject to RDA. Grandchildren and deeper are untouched from this item's walk.
- KeepAllChildrenSynchronized ("KeepAll"). TDS walks the full descendant tree. Strays at any depth are subject to RDA. KeepAll is sticky: when applied via "Select all children" in the Get Items dialog, TDS auto-applies KeepAll down through the descendants it added.
CIS values do not need to match across a chain. A KeepDirect parent with a KeepDirect child effectively covers two levels because each item's walk runs independently. Conversely, dropping CIS to None anywhere in the chain shields the subtree below that point from pruning.
3. Recursive Deploy Action (RDA)
RDA is a project-level setting on the Build tab of the TDS project's Property Pages, configured per build configuration (Debug, Release, QA, Production, etc.). It controls what the post-deploy processor does with stray items it finds in the target Sitecore database under any item whose CIS is KeepDirect or KeepAll. The setting is written into DeployedItems.xml at package generation time, so the action that runs at install is the one set when the package was built, not the one currently configured in the project. RDA is executed by HedgehogDevelopment.SitecoreProject.PackageInstallPostProcessor.dll during install of an .update or WebDeploy package, or by the TDS Sitecore Connector during a desktop deploy. RDA does not run during Quick Push or Sync.
Options:
- Ignore Sitecore items not in the project (default). Strays are left alone. RDA is effectively disabled. Safe default for environments where TDS is not the sole source of truth.
- Delete Sitecore items not in the project. Strays are permanently deleted. No Recycle Bin entry, no recovery without a database restore.
- Move Sitecore items not in the project to the Sitecore Recycle Bin. Strays are recycled via Sitecore's standard recycle mechanism (Archive database). Reversible from
/sitecore/Recycle Bin. The vendor's recommended value when RDA is enabled.
RDA never modifies or overwrites items. Item updates are governed entirely by Item Deployment.
4. How they combine
Two tables make the interactions explicit. The first covers the item itself. The second covers strays under it.
Item itself (Item Deployment alone)
| Item Deployment | Target has the item | Target missing the item |
|---|---|---|
| Once | Skip, no overwrite | Create |
| Always | Overwrite all serialized fields | Create |
| Never (Placeholder) | Untouched, not in manifest | Not created |
Stray descendants (CIS x RDA)
The parent item's Item Deployment value is irrelevant here. What matters is the parent's CIS and the project's RDA.
| Parent CIS \ RDA | Ignore | Delete | Recycle |
|---|---|---|---|
| None | Untouched | Untouched | Untouched |
| KeepDirect | Untouched | Direct children hard-deleted | Direct children recycled |
| KeepAll | Untouched | All descendants hard-deleted | All descendants recycled |
Full cross-check (Item Deployment x CIS x RDA)
| Item Deployment | Parent CIS | RDA = Ignore | RDA = Delete | RDA = Recycle |
|---|---|---|---|---|
| Once | None | Create if missing. Children untouched. | Same. Children untouched. | Same. Children untouched. |
| Once | KeepDirect | Create if missing. Direct strays untouched. | Create if missing. Direct strays HARD-DELETED. | Create if missing. Direct strays recycled. |
| Once | KeepAll | Create if missing. Descendant strays untouched. | Create if missing. ALL descendant strays HARD-DELETED. | Create if missing. ALL descendant strays recycled. |
| Always | None | Create or overwrite. Children untouched. | Same. Children untouched. | Same. Children untouched. |
| Always | KeepDirect | Create or overwrite. Direct strays untouched. | Create or overwrite. Direct strays HARD-DELETED. | Create or overwrite. Direct strays recycled. |
| Always | KeepAll | Create or overwrite. Descendant strays untouched. | Create or overwrite. ALL descendant strays HARD-DELETED. | Create or overwrite. ALL descendant strays recycled. |
| Never (Placeholder) | None | Not in manifest. Children untouched. | Same. | Same. |
| Never (Placeholder) | KeepDirect | Not in manifest. Post-step never visits it. CIS is dead. Children untouched. | Same. CIS on Placeholder is dead. Children untouched. | Same. Children untouched. |
| Never (Placeholder) | KeepAll | Same. CIS is dead. Children untouched. | Same. CIS on Placeholder is dead. Children untouched. | Same. Children untouched. |
The Placeholder rows matter: setting CIS on a Placeholder item buys nothing because the item is not in the manifest and the post-deploy processor never visits it.
5. What about the web database?
RDA only touches the database the TDS project targets, as configured on the General property page. That is normally master. The deletion or recycle does not reach web.
To get the deletion reflected in web, you publish. Two paths:
- Enable the "Publish After Deploy" post-deploy step on the Deploy tab of the TDS project. It uses Sitecore's standard Publishing Manager, so it also works with the Sitecore Publishing Service if installed. A smart publish from
mastertowebwill remove items fromwebthat no longer exist inmaster. - Publish manually or via your release pipeline after the TDS deploy completes.
Caveats:
- Recycle vs Delete makes no difference to web. Both end with the item not at its original path in
master. After publish,webis updated either way. With Recycle, the item lives in the Archive database and can be restored. - No publish, no change to web. If Publish After Deploy is off and nobody publishes, the deleted or recycled item stays visible on the website until somebody does.
- Publish scope must cover the item. A site-wide smart publish handles deletions cleanly. A narrow publish that excludes the item's path will not.
6. The multi-project / bundle case
What happens when the same Sitecore item is added to more than one TDS project with different CIS values? This is worth covering because it is the easiest way to create silent mutual destruction.
For independent sequential deploys (one .update or WebDeploy package per TDS project, installed one after the other), there is no merge. Each install runs its own post-deploy pass with its own manifest. If Project A has KAS + Recycle on item X and Project B has None on item X, Project A's install will recycle anything under X that is not in A's manifest, including items B owns. Then B's install creates them again, but the churn is real and order-dependent. There is no project-level "precedence", only execution order, and order can shift in CI.
For Package Bundling (one TDS project references others via Multi-Project Properties / Package Bundling), the bundling project produces a single combined package. Items from referenced projects are pulled into a single DeployedItems.xml at build time. I could not find documentation describing what TDS does when the same item ID appears in two referenced projects with different CIS values. Plausible behaviors are build error, last-write-wins, or first-write-wins. Anyone telling you with confidence without pointing at TDS source code or a vendor document is guessing. Verify by inspecting the bundled manifest before relying on it.
The fix in either case is structural, not configuration tuning:
- Pick exactly one project as the owner of any given subtree's CIS.
- Every other project that touches items below that ancestor must use NoChildSynchronization on the overlapping ancestors and on any of its own copies of those items.
- In a Helix solution this is enforced by convention: each module owns disjoint Sitecore subtrees.
Feature.Foo.Itemsowns/sitecore/templates/Feature/Fooexclusively, with KAS only on Foo's root. No other project serializes anything under/sitecore/templates/Feature/Foo. - For shared structural ancestors like
/sitecore/templates/Feature, mark them Placeholder in every project and place CIS on the leaf-most ancestor each project actually owns. - Add a build-time check (PowerShell or an MSBuild target) that scans all
.itemfiles across the solution's TDS projects and fails the build on duplicate IDs. TDS does not close this gap for you.
7. Cross-cutting gotchas
A consolidated list, from things that bite people in practice.
- CIS gates RDA. If CIS is None on a parent, RDA is dead under that parent. Easiest rule to forget when promoting a configuration from Dev to Production.
- CIS on a Placeholder is dead. A Placeholder is not in the manifest, so the post-deploy processor never reads its CIS.
- A Placeholder or Excluded item under a KeepAll ancestor will be pruned. From the manifest's perspective the item is a stray. The Ensure Parent Integrity validator catches this. Same hazard applies to Exclude from Configuration: in the configs where an item is excluded, it is absent from that config's manifest and looks like a stray to any KAS or KeepDirect ancestor.
- Standard Values are always overwritten regardless of DeployOnce. The Sitecore installer forces this. Use the Prevent Deploy Once Standard Values validator to surface it at build.
- RDA is captured at build time, not install time. A package built with RDA = Recycle will recycle on install even if the project has since been changed to RDA = Ignore. Inspect the
RecursiveDeployActionattribute inDeployedItems.xmlof the actual artifact being installed, not the current solution. - CI build flag. If
IsDesktopBuild=falseis not passed to MSBuild on the build server, items are packaged but not directly deployed. RDA is still in the manifest, so it activates wherever the package is later installed. This is the most common cause of "tested fine on Dev, deleted half my content on QA". - Multiple TDS projects with overlapping subtrees: see Section 6 above.
- Lightning Mode does not change RDA semantics. Items skipped by Lightning Mode for performance are still in the manifest, so they are not seen as strays.
- Locked items can fail a Delete RDA. TDS 5.1's release notes document a fix for the case where the deploy aborted on a locked item that RDA wanted to delete. Editor locks during deploy remain an operational issue.
- Renames and moves. Under KeepAll + Delete, a rename or move can transiently look like "old item gone, new item appears" in the wrong order, removing the old path before the new one is deserialized.
- Backups. Run a database backup before any deploy with RDA set to Delete or Recycle, in any environment beyond local Dev. Recycle is reversible per item; Delete is not.
- WebDeploy vs
.updatepackages. The post-deploy processor is faster and more reliable in the TDS WebDeploy installer than in legacy.updatepackages. WebDeploy is the right default on modern Sitecore.
8. Validators worth enabling
Turn these on for every CI build configuration. They are the only thing standing between a careless commit and an automated content massacre:
- Don't Sync Children with paths covering
/sitecore/content,/sitecore/media library, and any other editor-owned subtrees. Prevents accidentally setting CIS on editor-owned trees. - Ensure Parent Integrity. Catches Placeholder or Excluded items under a KAS or KeepDirect ancestor.
- Should be Deploy Once for content-like items.
- Prevent Deploy Once Standard Values. Surfaces the Sitecore installer's forced overwrite of Standard Values.
9. Defaults that hold up
These are conservative starting points. Tune for your project, but never the other direction.
- Per environment:
- Production and UAT: RDA = Ignore. Override case by case during decommission cycles, then revert.
- QA / CI: RDA = Move to Recycle Bin.
- Dev: RDA = Move to Recycle Bin.
- Per item:
- Item Deployment: DeployOnce as the default for everything. AlwaysUpdate only for developer-owned items (templates, renderings, layouts, branches). Placeholder for structural-only ancestors.
- CIS: None as the default. KeepDirect or KeepAll only on developer-owned subtrees. Never on
/sitecore/contentor/sitecore/media library.
- Per deploy:
- Enable Publish After Deploy if you want the deploy to affect what visitors see.
- Back up the target database before any deploy with RDA = Delete or Recycle.
- Reach for the right tool. RDA is a coarse instrument that assumes TDS is the sole source of truth for the marked subtree. If the goal is automated cleanup of decommissioned developer items in a tree where content authors are also active, prefer Razl or scripted Sitecore PowerShell Extensions instead.
TL;DR
- Item Deployment decides what happens to the item itself: Once, Always, Never (Placeholder).
- CIS decides whether TDS walks the item's descendants looking for strays: None, KeepDirect, KeepAll.
- RDA decides what to do with the strays: Ignore, Delete, Recycle.
- CIS gates RDA. If CIS is None, RDA does nothing under that item.
- RDA only touches the database the TDS project targets, normally
master. The web database changes only after a publish; use Publish After Deploy or publish in your pipeline. - Same item in multiple TDS projects with different CIS values is a structural bug, not a configuration to balance. Fix it at the project boundaries.
References: TDS Classic FAQ on teamdevelopmentforsitecore.com, the Hedgehog/Sitecore TDS documentation on hedgehogdevelopment.github.io/tds, TDS Classic 5.1 / 5.5 / 5.8 release notes, and Vincent Lui's TDS 5.8 review for the Publish After Deploy behavior. Multi-project bundle merge behavior is undocumented at the time of writing.