A modern, self-hostable genealogy web application built with Next.js 15, featuring interactive family tree visualization, research tracking, and role-based access control.
- 🌳 Interactive family tree visualization with D3.js
- 👤 Detailed person profiles with life events and timelines
- 🔍 Global search across people, places, and dates
- 📊 Research queue for tracking genealogy work
- 🏰 Notable relatives discovery (finds famous ancestors/cousins)
- 🗺️ Geographic map view of ancestors by location
- 📅 Timeline view of life events across generations
- 🛡️ Role-based access control (admin, editor, viewer)
- 🎨 Customizable branding, themes, and settings
- 🔐 Multiple auth options (Google OAuth, local passwords)
- 📧 Email invitations (AWS SES or SMTP)
- 🐳 Docker-ready for self-hosting
- 🔑 API key support for integrations
- 🤖 Research Tasks API for AI agent automation
- 📥 GEDCOM import/export for data portability
- 🖼️ Media management with S3 storage support
📸 Click to view application screenshots
Track your family tree at a glance with statistics, research progress, and recent activity.
Interactive multi-generational tree visualization with zoom, pan, and navigation controls.
Browse and search all individuals with quick access to ancestor/descendant trees.
Detailed person pages with life events, sources, photos, and research notes.
Manage family crests by surname—automatically inherited by all matching individuals.
Interactive map showing birth/death locations, migration paths, and timeline animation.
- Node.js 20+
- PostgreSQL 14+
- Google Cloud project (for OAuth)
git clone https://github.com/pmilano1/kindred.git
cd kindred
npm installCreate a PostgreSQL database:
# Create database
psql -U postgres -c "CREATE DATABASE genealogy;"
psql -U postgres -c "CREATE USER genealogy WITH PASSWORD 'your-password';"
psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE genealogy TO genealogy;"The application will create the necessary tables on first run. See the migrations/ directory for schema details.
- Go to Google Cloud Console
- Create a new project or select existing
- Enable the Google+ API
- Go to Credentials → Create Credentials → OAuth 2.0 Client ID
- Add authorized redirect URI:
http://localhost:3000/api/auth/callback/google - Copy the Client ID and Client Secret
cp .env.example .env.localEdit .env.local:
# Database
DATABASE_URL=postgresql://genealogy:your-password@localhost:5432/genealogy
# NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=generate-a-random-32-char-string
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secretGenerate NEXTAUTH_SECRET:
openssl rand -base64 32npm run dev- Log in with your Google account (first user becomes admin)
- Go to Admin → Site Settings
- Configure your family name and branding
├── app/ # Next.js App Router pages
│ ├── admin/ # Admin panel (users, settings)
│ ├── api/ # API routes (GraphQL, auth, health)
│ ├── person/[id]/ # Person detail pages
│ ├── tree/ # Family tree visualization
│ └── research/ # Research queue
├── components/ # React components
├── lib/ # Utilities
│ ├── graphql/ # GraphQL schema, resolvers, dataloaders
│ ├── auth.ts # NextAuth configuration
│ └── pool.ts # PostgreSQL connection
├── __tests__/ # Jest tests
└── public/ # Static assets
docker run -d \
-p 3000:3000 \
-e DATABASE_URL=postgresql://user:pass@host:5432/genealogy \
-e NEXTAUTH_URL=https://family.yourdomain.com \
-e NEXTAUTH_SECRET=your-secret-key \
-e INITIAL_ADMIN_PASSWORD=changeme \
ghcr.io/pmilano1/kindred:latestOn first startup with INITIAL_ADMIN_PASSWORD set, an admin user is created:
- Email:
admin@kindred.local(override withINITIAL_ADMIN_EMAIL) - Password: Your
INITIAL_ADMIN_PASSWORDvalue - You'll be prompted to change the password on first login
services:
kindred:
image: ghcr.io/pmilano1/kindred:latest
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://genealogy:password@db:5432/genealogy
NEXTAUTH_URL: http://localhost:3000
NEXTAUTH_SECRET: generate-a-random-secret
INITIAL_ADMIN_PASSWORD: changeme
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: genealogy
POSTGRES_PASSWORD: password
POSTGRES_DB: genealogy
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:The project includes GitHub Actions workflows for automated deployment:
- Push to
developbranch for CI checks - Create PR to
mainfor production deployment - Merge triggers automatic deployment to AWS App Runner
See CONTRIBUTING.md for the full workflow.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string |
NEXTAUTH_URL |
Yes | Public URL of your deployment |
NEXTAUTH_SECRET |
Yes | Random 32+ character secret |
GOOGLE_CLIENT_ID |
No | Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
No | Google OAuth client secret |
INITIAL_ADMIN_PASSWORD |
No | Bootstrap admin password (first run only) |
INITIAL_ADMIN_EMAIL |
No | Bootstrap admin email (default: admin@kindred.local) |
AUTH_TRUST_HOST |
No | Set to true for proxied environments |
Email is used for user invitations. Choose one provider:
AWS SES:
EMAIL_PROVIDER=ses
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
EMAIL_FROM=noreply@yourdomain.comSMTP:
EMAIL_PROVIDER=smtp
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
EMAIL_FROM=your-email@gmail.com💡 No email configured? Use
INITIAL_ADMIN_PASSWORDto bootstrap the first admin user without email.
Kindred exposes a GraphQL API for data access and integrations.
Access the interactive GraphQL playground at:
http://localhost:3000/api/graphql
Open this URL in your browser to explore the schema, run queries, and test mutations.
For programmatic access, create an API key in Admin → API Keys:
curl -X POST https://your-domain.com/api/graphql \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{"query": "{ stats { total_people total_families } }"}'# Get recent people
query {
recentPeople(limit: 10) {
id
name_full
birth_year
birth_place
}
}
# Search for people
query {
search(query: "John", first: 20) {
edges {
node {
id
name_full
}
}
totalCount
}
}Kindred provides a Research Tasks API designed for AI agent automation:
# Get actionable research tasks (ancestry gaps)
query {
researchTasks(filter: { gap_types: [END_OF_LINE], researchable_only: true }, first: 10) {
edges {
node {
person_id
gap_type # END_OF_LINE, MISSING_FATHER, MISSING_MOTHER
surname
location
year_min
year_max
sources { # Applicable genealogy sources
name
access_method # API, WEB_FETCH, CDP_BROWSER, MANUAL_ONLY
url_pattern
}
}
}
}
}
# Log a search attempt (prevents duplicate searches)
mutation {
logSearchAttempt(input: {
person_id: "abc123"
source_name: "Antenati"
result: NO_MATCH
notes: "Searched 1850-1860 birth records"
}) {
id
}
}
# Submit research findings with source citation
mutation {
submitResearch(input: {
person_id: "abc123"
new_father: { name_full: "Giovanni Rossi", birth_year: 1820 }
source: { source_name: "Antenati", action: "found", source_url: "https://..." }
confidence: "high"
}) {
success
changes_made
gaps_resolved
}
}The Research Tasks API identifies:
- END_OF_LINE: Ancestors with children but no known parents
- MISSING_FATHER/MOTHER: Ancestors with only one known parent
- Search parameters: Surname, location, year range for targeted searches
- Source recommendations: Prioritized by region and era
An experimental companion tool for automated genealogy research is available at genealogy-extractors. It can search multiple genealogy sources and stage findings for review.
⚠️ Use at your own risk. This is an experimental tool that automates web scraping of genealogy sites. It may violate terms of service of some sites. Review all findings before submitting to your tree.
Kindred uses version-controlled database migrations to manage schema changes. Migrations run automatically on every deployment using the industry standard pattern used by Prisma and Drizzle ORM.
- Migration files are defined in
lib/migrations.ts - On deployment,
migrate.jsruns as a separate step before the server starts - Migrations execute and exit with code 0 (success) or 1 (failure)
- Server starts only if migrations succeeded
This follows the same pattern as:
- Prisma:
npx prisma migrate deploy && node server.js - Drizzle:
node migrate.js && node server.js
Deployment Flow:
Docker Build → node migrate.js → (success) → node server.js
↓ (failure)
Exit with error
See docs/DEPLOYMENT.md for detailed deployment documentation.
Check migration status in the admin dashboard at /admin or via GraphQL:
query {
migrationStatus {
currentVersion
latestVersion
migrationNeeded
}
}If you need to run migrations manually:
# Connect to your database
psql $DATABASE_URL
# Check current version
SELECT version FROM schema_migrations ORDER BY version DESC LIMIT 1;
# Migrations are defined in lib/migrations.ts
# They run automatically on deployment, but you can trigger them by restarting the appMigrations not running?
- Check App Runner logs for
[Instrumentation]messages - Verify
scripts/start.shis being executed (look for[Startup]logs) - Ensure
DATABASE_URLis set correctly
Migration failed?
- Server won't start if migrations fail (by design)
- Check logs for error details
- Fix the issue and redeploy
📝 Note: Kindred currently manages genealogy records through the GraphQL API. This is great for bulk imports, scripting, and integration with other tools. A full-featured UI for adding and editing people, families, and events is on the roadmap—stay tuned!
See CONTRIBUTING.md for development workflow and guidelines.
MIT





