Tokenized access control transforms medical data permissions into non-fungible tokens (NFTs) or soulbound tokens (SBTs) that represent a specific user's right to view or use a dataset. Instead of a centralized database managing access lists, the blockchain ledger becomes the single source of truth for permissions. This model enables patient-centric data sovereignty, where individuals can grant, revoke, and audit access to their health information programmatically. Each access token is a smart contract that encodes rules such as the data scope (e.g., "MRI results from 2023"), the authorized party (a doctor's wallet address), the duration of access, and the permitted actions (view-only vs. compute).
How to Design a Tokenized Access Control System for Medical Data
How to Design a Tokenized Access Control System for Medical Data
A technical guide for developers on implementing a blockchain-based system to manage granular, auditable access to sensitive medical records using tokenized permissions.
The core architecture involves three main components: the off-chain data storage, the on-chain access ledger, and the access gateway. Sensitive medical records are never stored on-chain; they reside in encrypted form in decentralized storage solutions like IPFS or Arweave, or in compliant cloud vaults. The on-chain component, typically built on an EVM-compatible chain like Ethereum or a purpose-built healthcare blockchain such as Hedera, manages the minting, transfer, and revocation of access tokens. The access gateway is an API service that validates a requester's token ownership on-chain before decrypting and serving the corresponding off-chain data.
Smart contracts form the backbone of the permission logic. A primary contract, often following the ERC-721 or ERC-1155 standard, mints access tokens. Each token's metadata includes a cryptographic hash (e.g., keccak256) of the access policy. A separate verifier contract or a zero-knowledge proof circuit can be used for more complex, privacy-preserving checks without exposing patient identity. For example, a researcher could prove they hold a token granting access to "anonymous diabetes patient data" without revealing which specific patient datasets they are querying, using a ZK-SNARK like those implemented by zkSync or Aztec.
Implementing revocation and expiration is critical. Since NFTs can be transferred, using soulbound tokens (SBTs), which are non-transferable by design, prevents the sale of medical data access. For time-bound access, the smart contract can integrate a timestamp-based expiration mechanism, automatically invalidating the token after a set block height or date. Instant revocation can be achieved by having the gateway check a revocation registry—a separate smart contract or a merkle tree managed by the patient—that lists invalidated token IDs, ensuring revoked access is enforced in near real-time.
A practical code snippet for a basic access token minting function in Solidity illustrates the concept:
solidityfunction grantAccess(address _grantTo, string memory _dataHash, uint256 _expiry) public onlyOwner returns (uint256) { require(_expiry > block.timestamp, "Expiry must be in the future"); _tokenIdCounter.increment(); uint256 newTokenId = _tokenIdCounter.current(); _safeMint(_grantTo, newTokenId); _setTokenURI(newTokenId, _dataHash); // Stores hash of off-chain data location and policy expiryTime[newTokenId] = _expiry; emit AccessGranted(newTokenId, _grantTo, _expiry); }
This function mints an NFT to _grantTo, binds it to an off-chain data hash, and logs an expiry time.
Finally, consider compliance with regulations like HIPAA or GDPR. The system must ensure data encryption at rest and in transit, maintain an immutable audit trail of all access grants and data requests on-chain, and provide a clear mechanism for patient consent and data deletion rights. While the blockchain provides the immutable access log, the actual Personal Health Information (PHI) must remain in an encrypted, off-chain environment where deletion of the encryption keys can fulfill "right to be forgotten" requests. This hybrid architecture balances blockchain's transparency for auditing with the practical and legal requirements of handling sensitive medical data.
Prerequisites and System Architecture Overview
This guide outlines the technical foundations and architectural blueprint for building a tokenized access control system for sensitive medical data on the blockchain.
Designing a tokenized access control system for medical data requires a clear understanding of the core components and their interactions. The system's primary goal is to enable patient-centric data sovereignty, where individuals control access to their health records using cryptographic tokens. Key prerequisites include familiarity with smart contract development (Solidity for Ethereum, Rust for Solana), decentralized storage solutions like IPFS or Arweave, and zero-knowledge proof (ZKP) concepts for privacy-preserving verification. A working knowledge of healthcare data standards, such as FHIR (Fast Healthcare Interoperability Resources), is also essential for structuring the data payloads.
The system architecture is a hybrid model combining on-chain logic with off-chain data storage. At its core, a smart contract acts as the permission registry, managing the minting, transfer, and revocation of Non-Fungible Tokens (NFTs) or Soulbound Tokens (SBTs) that represent access rights. The actual medical data, such as MRI scans or lab results, is encrypted and stored off-chain in a decentralized file system. The on-chain token contains a pointer (like a content identifier, or CID) to this data and the cryptographic keys necessary for decryption, ensuring the blockchain only stores access metadata, not the sensitive data itself.
For patient privacy, the architecture must integrate advanced cryptographic techniques. Zero-Knowledge Proofs allow a patient to prove they have a valid condition or vaccination status without revealing the underlying record. Proxy re-encryption can enable secure data sharing between authorized parties without exposing the patient's private key. Furthermore, the system should implement a modular design with upgradable contracts (using proxies like the ERC-1967 standard) to allow for security patches and new feature integration without compromising existing user data or permissions.
How to Design a Tokenized Access Control System for Medical Data
A technical guide to implementing a blockchain-based access control system for sensitive medical records using tokenization and role-based permissions.
A tokenized access control system uses non-fungible tokens (NFTs) or semi-fungible tokens (SFTs) to represent granular permissions for sensitive data. For medical records, each patient's data is linked to a unique access token. Only wallets holding the corresponding token can perform specific actions, such as viewing a record or adding a lab result. This model moves beyond simple ownership, enabling fine-grained delegation where a patient can grant temporary, revocable access to a specialist without transferring data custody. The core smart contract must manage the minting, transfer, and burning of these permission tokens while enforcing strict logic.
The system architecture typically involves three core contracts. A Patient Registry contract maps patient identifiers (like a hashed national ID) to a primary wallet address and serves as the source of truth. A Permission Token contract, compliant with standards like ERC-1155 for its batch operations, mints tokens representing specific data access rights. Finally, a Data Access Manager contract acts as the gatekeeper, verifying token ownership before allowing any interaction with the off-chain data storage layer, such as IPFS or a decentralized storage network. Events from these contracts create a transparent, immutable audit trail of all access grants and revocations.
Implementing role-based logic within the token contract is critical. Instead of a simple ownerOf check, the contract should validate specific token attributes. For example, a token with ID 1 could grant VIEW access to a patient's general history, while token ID 2 grants APPEND access for lab results. The metadata or the contract logic itself defines these roles. The Data Access Manager would call a function like hasPermission(patientId, requesterAddress, requiredRole) which checks if the caller holds a token for that patient with the correct role. This separation of concerns keeps the permission logic upgradeable and auditable.
Key functions to implement include grantAccess(address provider, uint256 role, uint256 expiry), which mints a time-limited token to the provider's address, and revokeAccess(address provider, uint256 tokenId) for immediate revocation. For security, all sensitive operations must include access control modifiers like onlyPatientOrGuardian(patientId). It's also essential to design a consent renewal mechanism and handle edge cases like emergency access, which could be managed through a multi-signature wallet of accredited institutions. All state changes should emit detailed events for compliance with regulations like HIPAA's audit control requirement.
When integrating with off-chain data, use a content identifier (CID) from IPFS or Arweave as the pointer stored on-chain. The access manager contract returns the decryption key or the CID only after successful permission checks. For enhanced privacy, consider zero-knowledge proofs (ZKPs) to allow verification of credential validity (e.g., a doctor's license) without revealing the credential itself on-chain. Frameworks like the Solidity Role-Based Access Control (RBAC) library from OpenZeppelin can provide a foundational structure, but must be extensively customized for the nuanced consent and lifecycle management required by healthcare data.
Comparing Token Models for Access Control
A comparison of three primary token standards for implementing access control logic on-chain, detailing their suitability for a medical data system.
| Feature / Metric | ERC-20 (Fungible) | ERC-721 (NFT) | ERC-1155 (Semi-Fungible) |
|---|---|---|---|
Token Uniqueness | Configurable | ||
Batch Operations | Limited | ||
Gas Efficiency for Bulk Grants | Medium | Low | High |
Granular Permission Levels | Medium (via traits) | ||
Native Metadata Support | |||
Revocation Complexity | Burn/Transfer | Burn/Transfer | Batch Burn |
Ideal Use Case | Subscription Tiers | Individual Patient Consent | Role-Based & Resource Bundles |
Step 1: Implementing SBTs for Role Management
This guide details the foundational step of designing a tokenized access control system for medical data using Soulbound Tokens (SBTs). We will define roles, map them to on-chain permissions, and implement a basic smart contract structure.
A tokenized access control system replaces traditional centralized user databases with on-chain credentials. In healthcare, this means a patient's wallet address becomes their primary identifier, and their permissions are represented by non-transferable Soulbound Tokens (SBTs). Each SBT is a unique ERC-721 token minted to a specific wallet, encoding a user's role (e.g., PATIENT, DOCTOR, RESEARCHER). Because SBTs cannot be sold or transferred, they act as persistent, verifiable proof of a user's qualifications or status within the system, forming the bedrock of trust.
The first design task is to define the core roles and their associated permissions. A typical model includes: PATIENT (owner of the data, can grant/revoke access), PRIMARY_PHYSICIAN (full read/write access to their patients' records), SPECIALIST (time-bound, read-only access for consultations), and IRB_RESEARCHER (de-identified, aggregate data access for approved studies). These permissions are not stored in the data itself but are enforced by the smart contract logic that checks for the presence of a specific SBT before allowing any data transaction.
We implement this using a smart contract that extends the ERC-721 standard with a minting authority. Below is a simplified snippet of a contract that mints role-based SBTs. The key function mintRole can only be called by a trusted administrator (e.g., a hospital's credentialing wallet) and binds the role permanently to the recipient.
solidity// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract MedicalAccessSBT is ERC721 { address public admin; uint256 private _nextTokenId; mapping(uint256 => string) private _tokenRole; constructor() ERC721("MedicalAccess", "MASBT") { admin = msg.sender; } function mintRole(address to, string memory role) external { require(msg.sender == admin, "Only admin can mint"); uint256 tokenId = _nextTokenId++; _mint(to, tokenId); _tokenRole[tokenId] = role; // Soulbound: override transfer functions to revert } function getRole(uint256 tokenId) public view returns (string memory) { return _tokenRole[tokenId]; } }
To make the tokens truly soulbound, you must override the standard ERC-721 transferFrom and safeTransferFrom functions to always revert, preventing any transfer after minting. This is a critical security feature; a role credential must be irrevocably tied to its intended wallet. The admin retains the ability to revoke a role by burning the SBT, which is the equivalent of removing a user's access privileges in a traditional system. This creates a transparent and auditable log of role assignments and removals on the blockchain.
With the SBT contract deployed, the next step is to build the Access Control Layer. This is a separate contract or module within your application that holds the medical data references (often as pointers to off-chain storage like IPFS) and contains the business logic. Before any operation—viewRecord, addDiagnosis, shareWithSpecialist—the contract calls a modifier that checks balanceOf(msg.sender) and verifies the specific role encoded in the user's SBT. This pattern ensures that authorization is decentralized, transparent, and based on cryptographically verifiable proof.
This architecture offers significant advantages: patient sovereignty (patients hold their own access keys), cryptographic audit trails (all role grants/revokes are on-chain), and interoperability (a doctor's SBT from one institution could potentially be verified by another). The subsequent steps will cover storing encrypted data, implementing granular consent, and designing the user interface that interacts with these smart contracts.
Step 2: Creating Time-Bound Access Tokens
This section details the core smart contract logic for minting tokens that grant temporary, auditable access to sensitive medical data.
Time-bound access tokens are the core mechanism of our system. These are non-transferable NFTs (ERC-721 or ERC-1155) that represent a specific access grant. Each token is minted for a single patient's data record and encodes the access parameters: the dataHash being accessed, the grantee address (e.g., a specialist's wallet), and a critical expiryTimestamp. The token's tokenId can be derived from these parameters to ensure uniqueness. This design ensures each token is a self-contained, verifiable proof of permission.
The minting function is permissioned, typically callable only by the patient or a trusted custodian contract. It must validate the request before creating the token. Key checks include: verifying the caller is the data owner or their delegate, confirming the requested expiryTimestamp is in the future and within a system-defined maximum duration (e.g., 72 hours for a consultation), and ensuring no active, non-expired token already exists for the same dataHash and grantee pair to prevent duplicate grants.
Here is a simplified Solidity example for the minting logic using OpenZeppelin's ERC721 implementation:
solidityfunction grantAccess( address grantee, string calldata dataHash, uint256 expiryTimestamp ) external onlyDataOwner(dataHash) { require(expiryTimestamp > block.timestamp, "Expiry must be in future"); require(expiryTimestamp <= block.timestamp + MAX_GRANT_DURATION, "Grant duration too long"); require(!hasActiveAccess(grantee, dataHash), "Active grant already exists"); uint256 tokenId = uint256(keccak256(abi.encodePacked(dataHash, grantee, expiryTimestamp))); _safeMint(grantee, tokenId); // Store token metadata _tokenExpiry[tokenId] = expiryTimestamp; _tokenDataHash[tokenId] = dataHash; emit AccessGranted(tokenId, msg.sender, grantee, dataHash, expiryTimestamp); }
The onlyDataOwner modifier would check a registry mapping dataHash to owner address.
Once minted, any service (like a data gateway) can permissionlessly verify if access is valid. It checks three things: that the grantee possesses the token (using ownerOf(tokenId)), that the stored _tokenDataHash matches the requested data, and crucially, that block.timestamp < _tokenExpiry[tokenId]. This decentralized verification removes the need for a central auth server. After expiry, the token still exists in the grantee's wallet but will fail this check, functionally revoking access.
This architecture provides clear auditability and compliance. Every access grant and its parameters are immutably recorded on-chain via the AccessGranted event. Auditors or patients can query these events to see a complete history of who was granted access to which data record and for how long. The system enforces automatic revocation via time, reducing the risk of stale permissions. For emergency revocation before expiry, a separate function allowing the owner to burn the token would be required.
Step 3: Building the Central Access Logic Contract
This step focuses on the core smart contract that governs all access requests and permissions for the medical data system.
The Central Access Logic Contract is the system's brain. It doesn't store data itself but enforces the rules for who can access what. Its primary functions are to: manage a registry of authorized data providers (hospitals, clinics), handle access requests from researchers or insurers, validate requests against patient-defined policies, and log all access events immutably. This separation of logic from data storage is a key security and architectural best practice in Web3.
The contract's state includes critical mappings. A dataProviders mapping stores and verifies approved institutions. An accessPolicies mapping links a patient's wallet address to the IPFS hash of their consent document, which defines rules like "researcher X can access my oncology data for 30 days." A third mapping, accessGrants, tracks active permissions, storing the requester, data scope, and expiry timestamp to prevent unauthorized renewal.
The main workflow begins with requestAccess(dataHash, requesterInfo). This function checks if the caller is a registered provider, verifies a valid patient consent policy exists for the requested dataHash, and validates that the requesterInfo (e.g., researcher credentials) matches the policy's conditions. If all checks pass, it creates an entry in accessGrants and emits an AccessGranted event. This event acts as a verifiable, on-chain proof of permission for the data holder.
For implementation, we use Solidity 0.8.x with the OpenZeppelin library for Ownable and access control. The contract owner (a governance DAO or admin) can register new data providers. Critical functions use the onlyRegisteredProvider modifier. Time-based logic utilizes block.timestamp for grant expiration. All state changes are protected by reentrancy guards. You can view a foundational example on GitHub Gist.
This design ensures patient sovereignty. The patient's off-chain policy is the ultimate authority; the contract merely executes it transparently. Any access attempt that doesn't match a stored policy hash is automatically rejected. The immutable audit log provided by event emissions is crucial for compliance with regulations like HIPAA or GDPR, providing a tamper-proof record of all data access.
Integrating with Off-Chain Data Storage
This step details the critical design patterns for linking your on-chain access control logic to encrypted medical records stored off-chain, ensuring data privacy and system integrity.
A tokenized access control system for medical data must separate the access logic from the data storage. The on-chain smart contract manages permissions and token ownership, while the sensitive patient data itself is stored off-chain in a secure, encrypted format. This hybrid architecture leverages the blockchain's strengths—immutable, transparent access rules—while avoiding its weaknesses—high cost and public visibility for large, private datasets. The core challenge is creating a secure, verifiable, and efficient link between the two layers.
The standard pattern uses content-addressed storage (like IPFS or Arweave) and cryptographic proofs. When a new medical record is created, it is encrypted client-side using the patient's public key or a symmetric key. The resulting ciphertext is uploaded to the chosen storage network, which returns a unique content identifier (CID). Only this CID—a hash pointer to the data—is stored on-chain, often within the user's token metadata or a dedicated registry contract. This ensures no private data is ever written to the public ledger.
Access is granted via the token. When an authorized entity (like a doctor holding a valid access token) requests data, their wallet queries the smart contract. The contract verifies token ownership and permissions, then provides the off-chain CID. The user's client fetches the encrypted data from the storage network using the CID. Finally, decryption occurs locally using the user's private key or a key derived from a decentralized key management service. This end-to-end process ensures data is only decrypted by authorized parties.
For auditability, you can store proofs of storage or cryptographic commitments on-chain. For instance, you can store the hash of the encrypted data alongside its CID. Any future verifier can fetch the data from off-chain, re-hash it, and confirm it matches the on-chain commitment, proving the data has not been altered since the permission was granted. Protocols like Filecoin or services like Ceramic Network offer built-in verifiability for this purpose, adding a layer of data integrity assurance.
Implementing this requires careful client-side logic. Here's a simplified code flow for granting access and storing a record:
javascript// 1. Encrypt data off-chain const encryptedData = await encrypt(medicalRecord, patientPublicKey); // 2. Store on IPFS const cid = await ipfs.add(encryptedData); // 3. Update token metadata on-chain await accessContract.safeMint(patientAddress, tokenURI); // Where tokenURI points to a metadata JSON: { "encryptedDataCID": cid }
The corresponding access function in the smart contract would check the caller's token balance before allowing them to retrieve the stored CID.
Considerations for production systems include data availability (ensuring the off-chain storage is reliable), key management (using solutions like Lit Protocol for dynamic decryption rights), and compliance (mechanisms for data deletion or archiving to meet regulations like HIPAA or GDPR, which may involve key rotation or deletion). The on-chain component becomes an immutable log of access events, while the off-chain component provides the necessary flexibility and privacy for handling sensitive healthcare information.
Essential Tools and Resources
These tools and frameworks help developers design a tokenized access control system for medical data that meets privacy, auditability, and interoperability requirements. Each card focuses on a concrete component you can implement or evaluate.
Audit Trails and Compliance Logging
Medical data access requires immutable, inspectable audit logs for compliance and incident response.
Blockchain-native advantages:
- Every permission grant, transfer, or revocation is timestamped
- Onchain events provide non-repudiable audit records
- Logs can be correlated with offchain access events
Implementation details:
- Emit structured events for access changes, not data reads
- Index events using tools like The Graph for compliance queries
- Link onchain events to offchain system logs via request IDs
This design supports regulatory audits while minimizing onchain data exposure and avoiding performance bottlenecks.
Frequently Asked Questions
Common technical questions and solutions for implementing a secure, HIPAA-compliant tokenized access control system for medical data on-chain.
In a tokenized access control system, on-chain storage refers to data written directly to the blockchain (e.g., access permissions, audit logs, token metadata). This data is immutable and transparent. Off-chain storage is used for the actual Protected Health Information (PHI), such as MRI images or detailed patient notes, which is too large and sensitive for public ledgers.
A common pattern is to store a cryptographic hash (like a SHA-256 digest) of the PHI file on-chain, while the file itself is encrypted and stored off-chain in a decentralized storage network like IPFS or Arweave, or a compliant cloud service. The on-chain hash acts as a tamper-proof proof of the data's integrity. When access is granted via a token, the system provides the decryption key to the authorized party to retrieve and decrypt the off-chain file.
Security and HIPAA Compliance Considerations
Designing a blockchain-based system for medical data requires a security-first architecture that enforces HIPAA's Privacy and Security Rules. This guide outlines the core principles for building a compliant tokenized access control layer.
A tokenized access control system for Protected Health Information (PHI) must implement the core tenets of zero-trust security. This means every data access request, even from within a trusted network, must be authenticated, authorized, and logged. Smart contracts become the policy enforcement point, programmatically checking if a requester's token grants the specific minimum necessary permissions for a transaction. For example, a research token might only allow aggregated, de-identified data queries, while a clinician's token could permit decryption of specific patient records. This granularity is enforced on-chain, creating an immutable audit trail of all policy decisions.
HIPAA compliance mandates robust safeguards across administrative, physical, and technical dimensions. Your smart contract logic must encode administrative policies like role-based access control (RBAC). Technically, all PHI must be encrypted, with decryption keys managed separately from the blockchain—often using a secure, off-chain key management service (KMS). The blockchain stores only cryptographic proofs (like hashes of data or consent records) and access control logic. Physical and network security for the off-chain data storage (e.g., HIPAA-compliant cloud storage) remains critical, as the blockchain system is only as strong as its weakest infrastructural link.
Implementing patient consent is a primary use case. A patient can hold a non-transferable soulbound token (SBT) that represents their identity. To grant a research institution access, the patient signs a message approving a specific data use. This consent record, including its scope and expiry, is logged on-chain. The research institution's access token is then minted or activated by a smart contract that validates the patient's signature against the SBT. This creates a cryptographically verifiable chain of consent that is transparent and patient-auditable, satisfying HIPAA's requirement for patient authorization.
Auditability and breach notification are streamlined by the inherent properties of a public ledger. Every access event—token minting, policy update, data request—is timestamped and immutably recorded. In the event of a potential breach, the system can instantly provide a verifiable log of all transactions related to a specific dataset or user, drastically reducing the time to investigate and report as required by the HIPAA Breach Notification Rule. However, careful design is needed to ensure these logs do not themselves leak metadata that could be considered PHI.
Finally, key technical choices dictate compliance. Use a private or permissioned blockchain network (e.g., Hyperledger Fabric, Corda) where node operators are known, vetted entities (covered entities or business associates under HIPAA). This allows for private transactions and complex confidentiality agreements. The access tokens themselves should be non-fungible (NFTs) or soulbound (SBTs) to represent unique privileges, not tradeable assets. All smart contracts must undergo rigorous formal verification and security audits before handling any real PHI, as upgrades to live health data systems are highly constrained.
Conclusion and Next Steps
This guide has outlined the core components for building a secure, decentralized system for managing medical data access using tokenized permissions.
You have now explored the architectural blueprint for a tokenized access control system. The foundation is a smart contract managing a non-transferable Soulbound Token (SBT) like ERC-721 or ERC-1155, which acts as a permanent, non-sellable credential. Access logic is enforced on-chain, with functions like grantAccess and revokeAccess modifying a mapping that links a patient's wallet address to an array of authorized data requester addresses. This creates a transparent and immutable audit trail for all permission changes.
For the next phase, focus on integrating this on-chain logic with off-chain data storage. A common pattern is to store encrypted medical records on decentralized storage solutions like IPFS or Arweave, while storing the corresponding decryption keys or content identifiers (CIDs) on-chain, accessible only to wallets holding the requisite token. Implement a frontend dApp (using frameworks like React with ethers.js or viem) that allows patients to connect their wallet, view access logs, and manage permissions seamlessly. Ensure your UI clearly displays the current access list and the status of any pending transactions.
Critical next steps involve rigorous security auditing and testing. Use development frameworks like Hardhat or Foundry to write comprehensive unit and integration tests that cover edge cases: revocation of access, attempts by unauthorized wallets, and SBT minting permissions. Consider engaging a professional smart contract auditing firm before mainnet deployment. Additionally, plan for upgradability through proxy patterns (like Transparent or UUPS) to allow for future improvements without compromising existing patient data or permissions.
To extend the system's functionality, explore integrating zero-knowledge proofs (ZKPs) using libraries like Circom and snarkjs. This allows for more privacy-preserving queries, such as proving that a patient is over 18 without revealing their exact birthdate from their health record. You could also implement token-gated APIs, where your backend service verifies a user's SBT ownership via the EIP-4361 Sign-In with Ethereum standard before serving sensitive data, creating a complete end-to-end private data pipeline.
Finally, consider the real-world operational requirements. How will SBTs be initially minted and verified? You may need an onboarding contract with administrative functions restricted to verified healthcare providers. Establish clear legal and compliance frameworks for data handling. For further learning, study existing implementations in the space, such as Medibloc or Akash Network for decentralized compute, and review the EIP-4973 standard for Soulbound Tokens. Start with a testnet deployment on Sepolia or Polygon Mumbai to validate the entire user flow before committing to a production environment.