Building HIPAA-Compliant Apps: A Practical Guide
Row-level security, PHI-safe storage, audit logging, and BAA agreements. Everything you need to know to build healthcare applications that pass compliance reviews.
Why HIPAA Compliance Trips Up Engineering Teams
Most developers understand HIPAA in theory: protect health data, limit access, keep audit logs. In practice, the gap between "we've encrypted everything" and "we're actually HIPAA-compliant" is significant, and expensive to close post-launch.
We've built HIPAA-compliant applications for multiple healthcare startups. Here's the practical engineering checklist we work through on every project.
The Foundation: Covered Entities, PHI, and BAAs
Before writing a line of code, get clarity on three things:
- Are you a covered entity or a business associate? If you're building software that handles health data on behalf of healthcare providers, you're a business associate.
- What counts as PHI? Protected Health Information includes 18 categories of identifiers (names, dates, phone numbers, addresses, and more) when combined with health data.
- Do you have BAAs with your vendors? A Business Associate Agreement is required from every vendor who touches PHI: your cloud provider, database provider, email service, analytics platform, and error tracker.
Supabase offers BAAs on their Pro and Enterprise plans. Vercel does on Enterprise. AWS, GCP, and Azure all offer BAAs on paid plans. Get these signed before you store a single piece of real health data.
Database Architecture: Row-Level Security Is Not Optional
The most critical architectural decision for a HIPAA app is enforcing access control at the database layer. Do not rely solely on application code to gate access to PHI.
Supabase Row-Level Security
-- Patients can only read their own records
CREATE POLICY "patients_own_data" ON health_records
FOR SELECT
USING (patient_id = auth.uid());
-- Providers can read records for their assigned patients
CREATE POLICY "provider_patient_access" ON health_records
FOR SELECT
USING (
EXISTS (
SELECT 1 FROM provider_patient_relationships
WHERE provider_id = auth.uid()
AND patient_id = health_records.patient_id
)
);
With RLS enabled, even if your API layer has a bug that bypasses authorization, the database enforces the access rules. This is defence in depth.
Separate PHI from Non-PHI
Don't mix health records with product analytics events in the same table. Keep your PHI in isolated, encrypted tables with strict policies, and keep your analytics in a separate schema or service.
Encryption at Rest and in Transit
- At rest: Supabase encrypts all data at rest by default with AES-256. Verify this is enabled on your plan.
- In transit: Enforce HTTPS everywhere. Use Supabase's SSL-enforced connections. Never allow unencrypted database connections.
- Application-level encryption: For particularly sensitive fields (genetic data, mental health notes), consider field-level encryption in addition to disk encryption.
Audit Logging
HIPAA requires you to track who accessed or modified PHI and when. Build this from day one. Retrofitting it is painful.
CREATE TABLE phi_audit_log (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID NOT NULL,
action TEXT NOT NULL, -- 'read', 'create', 'update', 'delete'
table_name TEXT NOT NULL,
record_id UUID,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Trigger to log all access to health_records
CREATE OR REPLACE FUNCTION log_phi_access()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO phi_audit_log (user_id, action, table_name, record_id)
VALUES (auth.uid(), TG_OP, TG_TABLE_NAME, NEW.id);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
Store audit logs in a separate, append-only table. Audit log retention under HIPAA is six years.
Authentication and Access Controls
- Require MFA for all users who can access PHI
- Session timeouts: Automatic logout after inactivity (15 minutes is a common standard for clinical applications)
- Minimum necessary access: Role-based access control that limits each role to exactly the data it needs
- Emergency access procedures: Document and implement break-glass access patterns for genuine emergencies
Handling File Storage
If you store medical images, PDFs, or documents, use Supabase Storage with proper bucket policies:
// Signed URLs with short expiry for PHI documents
const { data } = await supabase.storage.from("medical-records").createSignedUrl(`${patientId}/${fileName}`, 300); // 5-minute expiry
Never use permanent public URLs for PHI documents.
What to Do Before Launch
- Complete a security risk assessment (required by HIPAA)
- Document your policies and procedures
- Train your team on HIPAA requirements
- Sign BAAs with all relevant vendors
- Run a penetration test
- Set up breach notification procedures (you have 60 days to notify affected individuals)
Building HIPAA-compliant applications is achievable without a dedicated compliance team. The key is building the right architecture from the start rather than bolting compliance on afterward.
If you're building a healthcare product and want to move fast without cutting compliance corners, let's talk.
Related Articles
How We Architect Telehealth Platforms From Scratch
Video calls, scheduling, prescriptions, and PHI. A practical walkthrough of the architecture decisions behind a production telehealth system.
Encrypting Patient Data: What You Actually Need to Do
Encryption at rest, in transit, and at the application layer. A no-nonsense guide to protecting PHI in modern web applications.