Skip to content
ArticlesPower Apps

Power Apps

Code Apps in Production: CSP, ALM, and Hard-Won Lessons

What you need to know before shipping a Code App to production - Content Security Policy, deployment pipelines, Dataverse quirks, and a pre-deploy checklist.

Building a Code App locally is straightforward. Getting it into production, and keeping it running reliably, is where the real lessons happen. This article covers the production concerns that official documentation glosses over.

CSP: The January 2026 enforcement

On January 30, 2026, Microsoft activated Content Security Policy enforcement for Code Apps. Every request to an external domain that is not explicitly whitelisted is now blocked by default.

This hit many teams hard. If your app loads fonts from a CDN, calls a third-party API, uses a JavaScript SDK, or even renders blob images, it might break in production without CSP configuration.

Content Security Policy flow diagram showing how CSP blocks or allows external requests from Code Apps

How to configure CSP

Navigate to Admin Center > Environments > Settings > Security > Content Security Policy.

Common directives you will need to update:

IssueDirective to modify
Third-party JS blockedscript-src: add the CDN domain
External CSS blockedstyle-src: add the CSS source
WebSocket connections deniedconnect-src: add wss:// URL
External auth service blockedconnect-src: add auth domains
Blob images not renderingimg-src: add data: and blob:
Web Workers failingworker-src: add blob:

CSP testing strategy

  1. Deploy to a development environment first
  2. Enable report-only mode in CSP settings
  3. Open browser DevTools > Console and look for CSP violation messages
  4. Add each blocked domain to the appropriate directive
  5. Test thoroughly, then switch to enforcement
  6. Repeat in QA before promoting to production

ALM: The connection reference pattern

The biggest ALM mistake is binding Code Apps to user-specific connections during development. These connections do not transfer across environments.

ALM pipeline diagram showing environment promotion from DEV to QA to PROD using managed solutions

The correct pattern

Use connection references instead of direct connections:

Code
# During development setup
pac code add-data-source \
  --apiId shared_commondataservice \
  --connectionRef <connection-ref-id> \
  --solutionId <solution-id>

Connection references are solution components. When you export a managed solution from DEV and import it into QA, the target environment provides its own connections for each reference. No manual rewiring required.

The deployment pipeline

Code
DEV:  pac code push --solutionName MySolution
      pac solution export --name MySolution --path ./export --managed

QA:   pac solution import --path ./export/MySolution_managed.zip
      (Configure connection ref mappings if first import)

PROD: Same managed solution, same process

Dataverse quirks to know

Null org URL on connections

This is the most common production issue. Connections created by pac code add-data-source often have a null organization URL, causing standard service methods to return empty results silently.

Always use the WithOrganization method variants:

Code
// WRONG — may return empty results
MicrosoftDataverseService.ListRecords('accounts', ...);

// CORRECT — explicitly passes the org URL
MicrosoftDataverseService.ListRecordsWithOrganization(
  'https://your-org.crm.dynamics.com',
  'accounts',
  ...
);

Create returns void

CreateRecordWithOrganization returns void. You cannot read the new record's ID from the response. Use a query-after-create pattern with retries to account for Dataverse's replication delay (~500ms):

Code
async function retryFind<T>(
  fn: () => Promise<T>,
  maxRetries = 3,
  delayMs = 500
): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    if (i > 0) await new Promise(r => setTimeout(r, delayMs));
    const result = await fn();
    if (result) return result;
  }
  return fn();
}

Invalid identifiers in generated code

The code generator may produce TypeScript identifiers with dots (e.g., MSCRM.IncludeMipSensitivityLabel), which are not valid TypeScript. Fix by replacing dots with underscores in the generated file.

Pre-deploy checklist

Before every production deployment:

  • npm run build completes with zero errors
  • No console.log statements in production code
  • WithOrganization used for all Dataverse calls
  • Connection references (not direct connections) for all data sources
  • CSP: all external domains whitelisted in the target environment
  • Bundle size < 500KB gzip (use code splitting with React.lazy)
  • Dark and light themes tested (if applicable)
  • Keyboard navigation works for all interactive elements
  • Error boundaries on critical components
  • Tested with a non-admin user account
  • Responsive layout verified (desktop + tablet minimum)
  • React version is 18.x or 19.x (both supported)

The bottom line

Code Apps in production are reliable once you know the gotchas: CSP configuration, connection references for ALM, and the WithOrganization pattern for Dataverse. The platform handles auth, hosting, and governance: your job is to get the data layer right and keep the bundle lean.

For the full technical reference, read:

The Complete Guide to Power Apps Code Apps


Sources