{"id":39608140,"url":"https://github.com/azoila/openmdm","last_synced_at":"2026-04-15T04:00:50.123Z","repository":{"id":333142744,"uuid":"1136061384","full_name":"azoila/openmdm","owner":"azoila","description":"OpenMDM is a modern, embeddable MDM SDK that gives you complete control over Android devices. Built for developers who need enterprise-grade device management without the complexity.","archived":false,"fork":false,"pushed_at":"2026-04-15T02:10:59.000Z","size":394,"stargazers_count":6,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-15T03:26:04.169Z","etag":null,"topics":["android","mdm","opensource","typescript"],"latest_commit_sha":null,"homepage":"https://openmdm-hono.vercel.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/azoila.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["azoila"]}},"created_at":"2026-01-17T02:04:32.000Z","updated_at":"2026-04-15T02:09:58.000Z","dependencies_parsed_at":"2026-01-24T05:02:14.668Z","dependency_job_id":null,"html_url":"https://github.com/azoila/openmdm","commit_stats":null,"previous_names":["azoila/openmdm"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/azoila/openmdm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azoila%2Fopenmdm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azoila%2Fopenmdm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azoila%2Fopenmdm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azoila%2Fopenmdm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/azoila","download_url":"https://codeload.github.com/azoila/openmdm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azoila%2Fopenmdm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31825515,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T18:05:02.291Z","status":"online","status_checked_at":"2026-04-15T02:00:06.175Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","mdm","opensource","typescript"],"created_at":"2026-01-18T08:01:46.065Z","updated_at":"2026-04-15T04:00:49.991Z","avatar_url":"https://github.com/azoila.png","language":"TypeScript","funding_links":["https://github.com/sponsors/azoila"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# OpenMDM\n\n**A modern, embeddable Mobile Device Management SDK for TypeScript**\n\n[![npm version](https://img.shields.io/npm/v/@openmdm/core.svg)](https://www.npmjs.com/package/@openmdm/core)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.5+-blue.svg)](https://www.typescriptlang.org/)\n[![Node.js](https://img.shields.io/badge/Node.js-20+-green.svg)](https://nodejs.org/)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)\n\n[Documentation](https://openmdm.dev/docs) | [Quick Start](#quick-start) | [Examples](./examples) | [Discord](https://discord.gg/openmdm)\n\n---\n\n**OpenMDM is the \"better-auth of MDM\"** - a flexible, framework-agnostic SDK that lets you add device management to any application without deploying a separate MDM server.\n\n\u003c/div\u003e\n\n\u003e [!CAUTION]\n\u003e **This project is under active development and is NOT ready for production use.**\n\u003e APIs may change without notice. Use at your own risk. We welcome contributions and feedback!\n\n## Why OpenMDM?\n\n### The Problem with Existing Solutions\n\n**Headwind MDM** and similar open-source MDM solutions are powerful but:\n- Require separate deployment (Java/Tomcat server)\n- Have their own database (can't use yours)\n- Limited integration options (no SDKs)\n- Session-based auth with legacy patterns\n- Hard to embed in existing applications\n\n**Commercial MDMs** (Intune, VMware, etc.) are:\n- Expensive at scale\n- Cloud-dependent\n- Vendor lock-in\n- Overkill for many use cases\n\n### The OpenMDM Solution\n\n```typescript\n// Install OpenMDM into YOUR application\nimport { createMDM } from '@openmdm/core';\nimport { drizzleAdapter } from '@openmdm/drizzle-adapter';\nimport { fcmPushAdapter } from '@openmdm/push-fcm';\n\nconst mdm = createMDM({\n  database: drizzleAdapter(db), // Your existing database\n  push: fcmPushAdapter({\n    credentialPath: './firebase-service-account.json',\n  }),\n  enrollment: {\n    deviceSecret: process.env.DEVICE_HMAC_SECRET,\n    autoEnroll: true,\n  },\n});\n\n// Now you have full MDM capabilities\nconst devices = await mdm.devices.list();\nawait mdm.devices.sendCommand(deviceId, { type: 'reboot' });\n```\n\n## Features\n\n- **Embeddable** - Works within your existing application, not as a separate service\n- **Framework Agnostic** - Use with Express, Hono, Fastify, Next.js, or any HTTP framework\n- **Database Agnostic** - Bring your own database with Drizzle, Prisma, or raw SQL\n- **Push Notifications** - FCM, MQTT, and WebSocket support\n- **S3 Storage** - Presigned URLs for APK uploads (AWS S3, MinIO, DigitalOcean Spaces)\n- **Webhooks** - HMAC-signed outbound webhooks with retry logic\n- **Plugin System** - Extend with kiosk, geofence, and custom plugins\n- **TypeScript First** - Full type safety with IntelliSense support\n\n## Packages\n\n| Package | Description | Status |\n|---------|-------------|--------|\n| [`@openmdm/core`](./packages/core) | Core MDM SDK - devices, policies, commands, events | Stable |\n| [`@openmdm/storage-s3`](./packages/storage/s3) | S3 storage adapter for APK uploads | Stable |\n| [`@openmdm/drizzle-adapter`](./packages/adapters/drizzle) | Database adapter for Drizzle ORM | Stable |\n| [`@openmdm/hono`](./packages/adapters/hono) | Hono framework adapter with REST API routes | Stable |\n| [`@openmdm/push-fcm`](./packages/push/fcm) | Firebase Cloud Messaging push adapter | Stable |\n| [`@openmdm/push-mqtt`](./packages/push/mqtt) | MQTT push adapter for private networks | Stable |\n| [`@openmdm/client`](./packages/client) | Device-side SDK for Android agents | Stable |\n| [`@openmdm/plugin-kiosk`](./packages/plugins/kiosk) | Kiosk/lockdown mode plugin | Stable |\n| [`@openmdm/plugin-geofence`](./packages/plugins/geofence) | Geofencing and location-based policies | Stable |\n| [`@openmdm/cli`](./packages/cli) | Command-line tools for administration | Stable |\n\n## Quick Start\n\n### 1. Install\n\n```bash\nnpm install @openmdm/core @openmdm/drizzle-adapter @openmdm/push-fcm\n# or\npnpm add @openmdm/core @openmdm/drizzle-adapter @openmdm/push-fcm\n```\n\n### 2. Configure\n\n```typescript\nimport { createMDM } from '@openmdm/core';\nimport { drizzleAdapter } from '@openmdm/drizzle-adapter';\nimport { fcmPushAdapter } from '@openmdm/push-fcm';\nimport { kioskPlugin } from '@openmdm/plugin-kiosk';\nimport { drizzle } from 'drizzle-orm/postgres-js';\nimport postgres from 'postgres';\n\n// Database connection\nconst db = drizzle(postgres(process.env.DATABASE_URL!));\n\n// Create MDM instance\nexport const mdm = createMDM({\n  database: drizzleAdapter(db),\n  push: fcmPushAdapter({\n    credentialPath: './firebase-service-account.json',\n  }),\n  enrollment: {\n    deviceSecret: process.env.DEVICE_SECRET!,\n    autoEnroll: true,\n  },\n  auth: {\n    deviceTokenSecret: process.env.JWT_SECRET!,\n  },\n  webhooks: {\n    endpoints: [{\n      id: 'main',\n      url: 'https://your-app.com/webhooks/mdm',\n      events: ['*'],\n      enabled: true,\n    }],\n    signingSecret: process.env.WEBHOOK_SECRET,\n  },\n  serverUrl: 'https://mdm.example.com',\n  plugins: [\n    kioskPlugin({ defaultExitPassword: 'admin123' }),\n  ],\n});\n```\n\n### 3. Use the API\n\n```typescript\n// List enrolled devices\nconst { devices, total } = await mdm.devices.list({ status: 'enrolled' });\n\n// Get device details\nconst device = await mdm.devices.get('device-123');\n\n// Send command\nawait mdm.commands.send({\n  deviceId: 'device-123',\n  type: 'sync',\n});\n\n// Create policy\nconst policy = await mdm.policies.create({\n  name: 'Kiosk Mode',\n  settings: {\n    kioskMode: true,\n    mainApp: 'com.example.app',\n    lockStatusBar: true,\n    lockNavigationBar: true,\n  },\n});\n\n// Apply policy to device\nawait mdm.devices.assignPolicy('device-123', policy.id);\n\n// Subscribe to events\nmdm.on('device.enrolled', async (event) =\u003e {\n  console.log('New device:', event.payload.device);\n});\n```\n\n### 4. Framework Integration\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eHono\u003c/b\u003e\u003c/summary\u003e\n\n```typescript\nimport { Hono } from 'hono';\nimport { honoAdapter } from '@openmdm/hono';\n\nconst app = new Hono();\napp.route('/mdm', honoAdapter(mdm));\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eExpress\u003c/b\u003e\u003c/summary\u003e\n\n```typescript\nimport express from 'express';\nimport { expressAdapter } from '@openmdm/express';\n\nconst app = express();\napp.use('/mdm', expressAdapter(mdm));\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eFastify\u003c/b\u003e\u003c/summary\u003e\n\n```typescript\nimport Fastify from 'fastify';\nimport { fastifyPlugin } from '@openmdm/fastify';\n\nconst app = Fastify();\napp.register(fastifyPlugin(mdm), { prefix: '/mdm' });\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eNext.js (App Router)\u003c/b\u003e\u003c/summary\u003e\n\n```typescript\n// app/api/mdm/[...path]/route.ts\nimport { nextjsHandler } from '@openmdm/nextjs';\nimport { mdm } from '@/lib/mdm';\n\nexport const { GET, POST, PUT, DELETE } = nextjsHandler(mdm);\n```\n\n\u003c/details\u003e\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                      YOUR APPLICATION                        │\n│                                                              │\n│    ┌────────────────────────────────────────────────────┐   │\n│    │                    OpenMDM SDK                      │   │\n│    │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌───────┐ │   │\n│    │  │ Devices │  │ Policies│  │Commands │  │ Push  │ │   │\n│    │  └─────────┘  └─────────┘  └─────────┘  └───────┘ │   │\n│    │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌───────┐ │   │\n│    │  │  Apps   │  │ Groups  │  │ Events  │  │Webhooks│ │   │\n│    │  └─────────┘  └─────────┘  └─────────┘  └───────┘ │   │\n│    └────────────────────────────────────────────────────┘   │\n│                              │                               │\n│              ┌───────────────┼───────────────┐              │\n│              │               │               │              │\n│      ┌───────▼───────┐ ┌────▼────┐ ┌───────▼───────┐       │\n│      │ Your Database │ │  FCM/   │ │ Android Agent │       │\n│      │   (Drizzle)   │ │  MQTT   │ │    (Kotlin)   │       │\n│      └───────────────┘ └─────────┘ └───────────────┘       │\n└─────────────────────────────────────────────────────────────┘\n```\n\n## Android Agent\n\nThe Android Agent is maintained in a separate repository for easier customization and forking:\n\n**Repository**: [openmdm/openmdm-android](https://github.com/openmdm/openmdm-android)\n\n### Features\n\n- Device enrollment with QR code or token\n- FCM push notification support\n- Automatic heartbeat/check-in scheduling\n- Command processing (sync, lock, wipe, app install, etc.)\n- Device Owner / Device Admin capabilities\n- Silent app installation and permission granting\n- Kiosk mode support\n- Location reporting\n\n### Getting Started\n\n```bash\n# Clone the Android agent\ngit clone https://github.com/openmdm/openmdm-android\n\n# Build the full agent app\ncd openmdm-android\n./gradlew :agent:assembleRelease\n\n# Or use the library in your own app\nimplementation(\"com.github.openmdm:openmdm-android:library:0.1.0\")\n```\n\nSee the [openmdm-android README](https://github.com/openmdm/openmdm-android) for full documentation.\n\n## Push Notification Providers\n\n### FCM (Firebase Cloud Messaging)\n\nRecommended for devices with Google Play Services.\n\n```typescript\nimport { fcmPushAdapter } from '@openmdm/push-fcm';\n\nconst push = fcmPushAdapter({\n  credentialPath: './firebase-service-account.json',\n  dataOnly: true,\n});\n```\n\n### MQTT\n\nFor private networks, air-gapped environments, or devices without Google Play Services.\n\n```typescript\nimport { mqttPushAdapter } from '@openmdm/push-mqtt';\n\nconst push = mqttPushAdapter({\n  brokerUrl: 'mqtt://mqtt.example.com:1883',\n  username: 'mdm-server',\n  password: 'secret',\n  qos: 1,\n});\n```\n\n## Plugins\n\n### Kiosk Mode\n\nLock devices to a single app or set of apps.\n\n```typescript\nimport { kioskPlugin } from '@openmdm/plugin-kiosk';\n\nconst mdm = createMDM({\n  plugins: [\n    kioskPlugin({\n      defaultExitPassword: 'admin123',\n      allowRemoteExit: true,\n      autoRestart: true,\n    }),\n  ],\n});\n```\n\n### Geofencing\n\nLocation-based policies and alerts.\n\n```typescript\nimport { geofencePlugin } from '@openmdm/plugin-geofence';\n\nconst mdm = createMDM({\n  plugins: [\n    geofencePlugin({\n      onEnter: async (device, zone) =\u003e {\n        await mdm.devices.assignPolicy(device.id, 'office-policy');\n      },\n      onExit: async (device, zone) =\u003e {\n        await mdm.devices.assignPolicy(device.id, 'default-policy');\n      },\n    }),\n  ],\n});\n```\n\n## CLI Tools\n\n```bash\n# Initialize project\nnpx openmdm init\n\n# Run database migrations\nnpx openmdm migrate\n\n# List devices\nnpx openmdm device list\nnpx openmdm device show \u003cdeviceId\u003e\n\n# Manage policies\nnpx openmdm policy list\nnpx openmdm policy create\nnpx openmdm policy apply \u003cpolicyId\u003e \u003cdeviceId\u003e\n\n# Generate enrollment\nnpx openmdm enroll qr --output enrollment.png\nnpx openmdm enroll token\n\n# View statistics\nnpx openmdm stats\n```\n\n## Project Structure\n\n```\nopenmdm/                          # This repository (SDK monorepo)\n├── packages/\n│   ├── core/                     # Core MDM SDK\n│   ├── storage/s3/               # S3 storage adapter\n│   ├── adapters/\n│   │   ├── drizzle/              # Drizzle ORM adapter\n│   │   └── hono/                 # Hono framework adapter\n│   ├── push/\n│   │   ├── fcm/                  # FCM push adapter\n│   │   └── mqtt/                 # MQTT push adapter\n│   ├── plugins/\n│   │   ├── kiosk/                # Kiosk mode plugin\n│   │   └── geofence/             # Geofencing plugin\n│   ├── client/                   # Device-side SDK (TypeScript types)\n│   └── cli/                      # CLI tools\n├── examples/                     # Example applications\n└── docs/                         # Documentation website\n\nopenmdm-android/                  # Separate repository\n├── agent/                        # Full-featured MDM agent app\n├── library/                      # Core MDM library (embeddable)\n└── docs/                         # Android-specific docs\n```\n\n## Comparison\n\n| Feature | OpenMDM | Headwind MDM | Commercial |\n|---------|---------|--------------|------------|\n| Embeddable | Yes | No | No |\n| Use your DB | Yes | No | No |\n| Self-hosted | Yes | Yes | Some |\n| Framework agnostic | Yes | No | No |\n| Plugin system | Yes | Limited | Limited |\n| Webhooks | Yes | Enterprise | Yes |\n| S3 Storage | Yes | No | Yes |\n| Kiosk mode | Yes | Yes | Yes |\n| Device Owner | Yes | Yes | Yes |\n| TypeScript | Native | No | No |\n| Price | Free | Free/Paid | $$$ |\n\n## Development\n\n```bash\n# Install dependencies\npnpm install\n\n# Build all packages\npnpm build\n\n# Run tests\npnpm test\n\n# Type check\npnpm typecheck\n\n# Watch mode\npnpm dev\n```\n\n## Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n- [Code of Conduct](CODE_OF_CONDUCT.md)\n- [Security Policy](SECURITY.md)\n\n## Community\n\n- [Discord](https://discord.gg/openmdm) - Chat with the community\n- [GitHub Discussions](https://github.com/openmdm/openmdm/discussions) - Ask questions, share ideas\n- [Twitter](https://twitter.com/openmdm) - Updates and announcements\n\n## Documentation\n\n- [API Reference](https://openmdm.dev/docs/api)\n- [Architecture \u0026 Design](./docs/MDM-ANALYSIS-AND-ARCHITECTURE.md)\n- [Migration from Headwind](./docs/migration-headwind.md)\n- [Android Agent Setup](https://github.com/openmdm/openmdm-android)\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n\n## Acknowledgments\n\n- [Headwind MDM](https://h-mdm.com/) - For years of MDM knowledge\n- [better-auth](https://better-auth.com/) - For the embeddable SDK design pattern\n- [Android Enterprise](https://developers.google.com/android/work) - For the platform APIs\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**Built with TypeScript. Inspired by [better-auth](https://github.com/better-auth/better-auth).**\n\n[Documentation](https://openmdm.dev) | [GitHub](https://github.com/openmdm/openmdm) | [Discord](https://discord.gg/openmdm)\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazoila%2Fopenmdm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fazoila%2Fopenmdm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazoila%2Fopenmdm/lists"}