A new app should not begin with a week of copying authentication code, guessing where environment settings belong, and rediscovering how the last product logged errors. It should begin with a small, inspectable foundation that lets the builder test the product’s distinctive promise. That is the job of an app template system.
The difficult word is system. A repository copied once is a starting point. A template system includes the starter, its supported versions, the checks that prove it still starts correctly, and a way to tell downstream owners when inherited assumptions need attention. Without those pieces, yesterday’s shortcut becomes tomorrow’s collection of divergent security settings and obsolete packages.
The central question is what belongs in a template so a new product starts with useful defaults without inheriting a business it has not yet earned. The answer is a narrow executable foundation: structure, configuration contracts, safe integration seams, a small set of checks, and an explicit upgrade relationship. Product workflows belong in the app. Frequently changing shared behavior may belong in a maintained dependency. The template makes that distinction visible.
This chapter belongs to The AI Software Factory, within the AI collection. The shared platform explains which capabilities multiple products can share. Here the focus is the moment a new repository is created and the obligations that creation carries forward.
Begin with a reproducible empty product
An effective starter should pass a modest but meaningful demonstration. A builder creates a repository, supplies documented development configuration, installs the declared dependencies, starts the application, and runs its checks. A second builder should be able to repeat the same sequence without consulting the first builder’s memory.
That demonstration is deliberately smaller than a finished product. A blank dashboard, health endpoint, or sample page is enough to exercise the paths the starter promises. A template that displays an impressive fictitious business dashboard may conceal unnecessary domain assumptions. Someone must remove those assumptions before building the real product, and the removal can break code that appeared essential.
Define the first successful run in observable terms. The page loads. A test verifies that a request reaches the application. A missing required setting produces a useful development error. The production build completes using the supported runtime. No real customer data or live payment credential is needed for the demonstration. These are acceptance conditions for the starter, not evidence that the resulting business will work.
The supported runtime matters because a template is tested in a particular environment. Record the language runtime, package manager, relevant platform assumptions, and date of the latest successful starter check. Do not describe an untested collection of combinations as supported merely because their names can be placed in a matrix. A small verified compatibility promise is more useful than an expansive fictional one.
The starter also needs a clear way to remove sample material. Sample names, placeholder accounts, test recipients, and demonstration routes should be easy to find. A creation check can fail if forbidden placeholders remain in a release configuration. The purpose is to prevent a copied example from quietly becoming the production identity of a new app.
Separate copied structure from maintained behavior
GitHub’s documentation makes an important distinction between repositories created from templates and forks. A template creates a new project with its own initial history, while a fork retains the parent history and its relationship to that project. A template is therefore useful for starting work, but copying files does not create a downstream update mechanism. That mechanism must be designed separately. GitHub’s template documentation supports the distinction; it does not promise automatic synchronization.
Consider an error-reporting wrapper used by six products. If the wrapper is copied into every new app, its next correction requires identifying and editing six variants. If the stable interface can live in a shared package, each app can receive a reviewed package update. The template can install and demonstrate that package without becoming its permanent delivery channel.
Some structure is naturally copied. A product README, local configuration example, initial test layout, and sample route will change with the new product. The expectation is divergence. Other behavior is valuable precisely because products should not maintain separate versions: a supported authentication adapter, a common audit event format, or a central billing client. The expectation there is compatibility through a maintained interface.
A third category belongs outside both template and package. Account ownership, provider credentials, production data classification, and customer retention promises are app-specific decisions. A starter may ask for them or provide empty fields, but it should not decide them by copying the choices of the app that inspired it.
For every template item, write one sentence explaining whether it is expected to diverge, update through a dependency, or require product-specific configuration. This simple classification prevents the starter from becoming an accidental framework. The component catalog can record maintained building blocks; the template records how a new app initially assembles them.
Authentication should be a seam with tested behavior
A starter can demonstrate authentication without assuming every product has the same identity model. It can define how an application receives a verified identity, where authorization checks belong, and how unauthenticated requests are handled. Those are useful structural decisions. Whether a product serves individual accounts, organizations, temporary guests, or a mixture requires its own design.
Suppose the starter includes a protected sample route. The associated checks should show that an unauthenticated request is rejected or redirected as intended, that an authenticated request can enter, and that a second account cannot obtain the first account’s private sample object. The last condition matters because successful login is not sufficient evidence of correct resource access.
Keep the identity provider adapter replaceable through a documented interface where practical. Replaceable does not mean the product can switch providers without migration work. It means the app’s business logic does not casually depend on provider-specific request details everywhere. A supported adapter still needs version checks, failure handling, and a migration plan when its behavior changes.
Avoid shipping a development bypass that can become production behavior through a forgotten flag. If a local shortcut exists, constrain its environment and test the constraint. Give it an unmistakable name. A starter that is easy to demonstrate but easy to misconfigure has transferred work into a more dangerous stage.
Authorization also needs an owner. The template may include a default policy example, but a new app must identify its actual resources and roles before release. A copied “admin” label is not a complete permission model. The starter’s checklist should force a review of account boundaries rather than let a sample role imply that the question has already been answered.
Billing defaults should clarify boundaries
Many new software products do not need billing on their first day. Some validate a workflow manually before accepting subscriptions. Others sell a one-time service or include usage in an existing customer agreement. A useful template should make payment integration available without turning every experiment into a subscription application.
The seam can define where the application receives a verified commercial entitlement. It should distinguish a provider’s payment event from the app’s decision about access. A payment success, a refund, a failed renewal, and a canceled subscription have different implications. The template should not bury those decisions in a route handler that new builders are unlikely to read.
A sample billing adapter should use a test environment and clearly labeled sample records. Its checks can exercise a known event fixture, reject an invalid fixture, and show how duplicate delivery is handled. Those are starter checks. They do not establish that a live provider account, pricing policy, customer tax treatment, or contractual promise is correct.
Leave price identifiers and production account references empty until the product owner supplies them. A copied live identifier can send money or access decisions into the wrong business. The starter should document which settings select the commercial account and which settings select the product offer, because those are separate mistakes with different consequences.
If billing is optional, test the app without it. A disabled capability should fail in a clear, intentional way when someone reaches its route. It should not half-initialize and produce confusing errors elsewhere. Optional modules increase the number of supported configurations; each option earns its place only when the team can explain and verify its behavior.
Observability should answer a product owner’s first questions
A newly created app needs enough visibility to distinguish a failed deployment from a failed customer workflow. It does not need an elaborate monitoring estate copied from a much larger company. Start with structured events, a correlation identifier where requests cross boundaries, and a small documented set of operational signals.
The template can provide a consistent event envelope: application identifier, environment, timestamp, operation, outcome, and correlation reference. It should avoid placing secrets, full customer documents, or unnecessary personal data in default logs. A debugging convenience copied into many products can become an expensive data-handling problem.
Define example signals in terms of what they mean. A process health check says something different from “a customer completed the core workflow.” A successful deployment does not prove that an external service works. A high request count does not prove value. The sample dashboard should help the owner understand those distinctions instead of displaying green indicators without context.
A starter should also demonstrate failure. Trigger a controlled local dependency failure and confirm that the app reports a useful outcome without exposing a credential. Include the expected behavior in the README. If all starter examples are successful requests, builders will have to invent the failure path under pressure after launch.
Logging dependencies should have a fallback policy. If the logging destination is temporarily unavailable, should the app continue serving the core workflow, buffer a bounded amount, or reject a particular operation because an audit record is mandatory? The right answer depends on the product. The template can expose the decision and provide a conservative sample, but it cannot silently choose one policy for every possible app.
Give tests a job beyond proving the sample page exists
The first tests establish that the starter’s promises are still true. They are not a decorative percentage of coverage. A useful starter suite might verify startup, configuration validation, access boundaries, an adapter failure, a sample data migration, and the production build. Each test should correspond to a behavior an app will otherwise inherit without inspection.
A product should replace or extend the sample tests with its own acceptance cases. Keep a distinction between template compatibility checks and product behavior checks so owners know why a failure matters. A starter update may require changing a configuration contract while preserving the product’s workflow. A product change may break its workflow while leaving every template check green.
The testing chapter develops broader testing strategy. At template creation, the narrower obligation is to supply a runnable baseline and demonstrate how the builder adds a case. Include one realistic example of a negative outcome, not just a successful response. Builders tend to reproduce the patterns that the starter makes easiest.
Do not ship tests that require real production credentials just to prove the app starts. External integration checks can be a separate, clearly labeled step with appropriate access. The default local suite should be reproducible and safe for a new builder. Otherwise a template encourages workarounds such as disabling checks or borrowing credentials from another app.
Treat generated template output as the test subject. It is possible for the source template to pass while the newly created repository contains a missing file, wrong import, or leftover placeholder. A release check should create a disposable app from the template and run the promised sequence there. That is the experience the template is selling to its users.
Version the creation contract
Give the template a release identifier and write it into the generated app’s record. The record should distinguish the template version at creation from the versions of current shared dependencies. An app created from starter version three may later use package version seven. Describing both with a single “current” label hides which assumptions actually changed.
A template release note should describe behavior changes and required follow-up. “Updated dependencies” is not enough when the update changes configuration names, routing conventions, or permission behavior. Tell owners what they must review, what can be checked mechanically, and where a manual decision remains.
Use a modest compatibility policy. For example, a proposed system might support the current template release and one prior release for a defined period. That is a policy choice, not an industry requirement. It becomes credible only when someone owns the upgrade work and the team has enough capacity to maintain both lines.
Some copied files cannot be upgraded automatically because products have intentionally edited them. An upgrade tool should detect that ambiguity and show a reviewable change rather than overwrite the file. A conflict is useful information: it says the app has diverged from the original assumption. Treating that divergence as an inconvenience to erase defeats the purpose of copying product-owned structure.
Record retirement as well as release. A vulnerable or unsupported template should stop being the default for new apps even if existing apps need time to migrate. The change in creation policy and the change in installed products are separate actions. Owners need both visible dates, because stopping new copies does not remove old obligations.
Measure drift without pretending every difference is wrong
Template drift is any meaningful difference between the foundation a product uses and the foundation the team currently supports. Some drift is an intentional product decision. Some is a forgotten update. A useful report separates them by asking the owner for a reason, not by assuming that all apps should converge on identical files.
A drift record can identify an outdated adapter, an unsupported runtime, an altered access middleware, or a missing operational signal. It should link to the relevant code and state the consequence. “Different from starter” is weak evidence; “this app still depends on a configuration contract removed from the supported adapter” is actionable.
The app registry is the place to connect that report to a running product and an accountable owner. The template system supplies the inheritance history. The registry supplies the current product relationship. Neither can substitute for the other: a perfect starter inventory does not tell you which deployed product still uses it.
Avoid expanding the template simply because two apps contain similar code. Repetition can reveal a stable shared need, but it can also be a temporary resemblance between different workflows. Before adding an item, ask whether a new product needs it on creation, whether its contract is stable, and whether the maintenance cost is justified.
A counterexample is useful. A small internal report tool may need no login integration because access is enforced at an existing gateway. A public subscription app does need application-level identity and entitlement behavior. One universal template might force the report tool to carry unused machinery. Two small supported variants, or a clearly tested optional module, may be easier to maintain than an ever-growing universal starter.
What Would We Do at Salars?
We would propose one narrow starter for a bounded product class before attempting a universal app generator. The first release would specify its runtime, local configuration contract, identity seam, optional billing seam, event envelope, and a small acceptance suite. It would include a clean creation example and a generated-app check. This is a proposed design, not a claim that Salars has measured a reduction in development time.
We would register each created app with its template origin and the owner responsible for reviewing upgrades. Product-specific values would be supplied through the creation process; live credentials would not be copied. Shared adapters would be maintained as dependencies where their interfaces justified that approach. Product structure would remain deliberately editable.
Before promoting a template version, we would create a disposable product, exercise success and failure paths, and inspect the generated configuration. We would also use a counterexample product that does not need billing to make sure optionality is real. A release would stop if the starter required undocumented manual repairs or accidentally referenced a production account.
The comparison would be an explicit baseline: creating the same small product using the previous documented starting process. Success would mean fewer unresolved setup decisions and a correct, reviewable initial app, while preserving the acceptance cases. We would record elapsed work and follow-up corrections without claiming that a faster first commit proves a faster or better product. Revalidation would follow a runtime change, adapter change, or significant failure in a downstream app.
The template earns its place when it makes necessary decisions visible and repeatable. It loses its value when it replaces product judgment with copied assumptions. A maintained starter should let the builder spend more attention on the customer’s problem while leaving an understandable trail of everything the new app inherited.
Sources
- GitHub: Creating a repository from a template — repository creation behavior and the distinction between templates and forks.
The creation contract, proposed checks, upgrade policy, and Salars experiment in this article are design proposals derived from that boundary and the series’ operational requirements. They are not performance findings from a deployed template system.
Loading comments…