diff --git a/package-lock.json b/package-lock.json
index 05fc947..65b5aa5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "auth0-source-control-extension-tools",
-  "version": "4.4.3",
+  "version": "4.5.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index 31dfb1e..7be5922 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "auth0-source-control-extension-tools",
-  "version": "4.4.3",
+  "version": "4.5.0",
   "description": "Supporting tools for the Source Control extensions",
   "main": "lib/index.js",
   "scripts": {
@@ -8,6 +8,7 @@
     "prepare": "npm run build",
     "release": "git tag $npm_package_version && git push --tags && npm publish",
     "lint:js": "eslint --ignore-path .gitignore --ignore-pattern webpack .",
+    "lint:fix": "eslint --fix --ignore-path .gitignore --ignore-pattern webpack .",
     "test": "npm run test:pre && cross-env NODE_ENV=test nyc mocha tests/mocha.js './tests/**/*.tests.js'",
     "test:watch": "cross-env NODE_ENV=test mocha tests/mocha.js ./tests/**/*.tests.js ./tests/*.tests.js --watch",
     "test:pre": "npm run test:clean && npm run lint:js",
diff --git a/src/auth0/handlers/index.js b/src/auth0/handlers/index.js
index 9436175..16d0b8a 100644
--- a/src/auth0/handlers/index.js
+++ b/src/auth0/handlers/index.js
@@ -20,6 +20,7 @@ import * as roles from './roles';
 import * as branding from './branding';
 import * as prompts from './prompts';
 import * as migrations from './migrations';
+import * as organizations from './organizations';
 
 export {
   rules,
@@ -43,5 +44,6 @@ export {
   roles,
   branding,
   prompts,
-  migrations
+  migrations,
+  organizations
 };
diff --git a/src/auth0/handlers/organizations.js b/src/auth0/handlers/organizations.js
new file mode 100644
index 0000000..03ba427
--- /dev/null
+++ b/src/auth0/handlers/organizations.js
@@ -0,0 +1,191 @@
+import _ from 'lodash';
+import DefaultHandler, { order } from './default';
+import { calcChanges } from '../../utils';
+import log from '../../logger';
+
+export const schema = {
+  type: 'array',
+  items: {
+    type: 'object',
+    properties: {
+      name: { type: 'string' },
+      display_name: { type: 'string' },
+      branding: { type: 'object' },
+      metadata: { type: 'object' },
+      connections: {
+        type: 'array',
+        items: {
+          type: 'object',
+          properties: {
+            connection_id: { type: 'string' },
+            assign_membership_on_login: { type: 'boolean' }
+          }
+        }
+      }
+    },
+    required: [ 'name' ]
+  }
+};
+
+export default class OrganizationsHandler extends DefaultHandler {
+  constructor(config) {
+    super({
+      ...config,
+      type: 'organizations',
+      id: 'id',
+      identifiers: [ 'name' ]
+    });
+  }
+
+  async deleteOrganization(org) {
+    await this.client.organizations.delete({ id: org.id });
+  }
+
+  async deleteOrganizations(data) {
+    if (this.config('AUTH0_ALLOW_DELETE') === 'true' || this.config('AUTH0_ALLOW_DELETE') === true) {
+      await this.client.pool.addEachTask({
+        data: data || [],
+        generator: item => this.deleteOrganization(item).then(() => {
+          this.didDelete(item);
+          this.deleted += 1;
+        }).catch((err) => {
+          throw new Error(`Problem deleting ${this.type} ${this.objString(item)}\n${err}`);
+        })
+      }).promise();
+    } else {
+      log.warn(`Detected the following organizations should be deleted. Doing so may be destructive.\nYou can enable deletes by setting 'AUTH0_ALLOW_DELETE' to true in the config
+      \n${data.map(i => this.objString(i)).join('\n')}`);
+    }
+  }
+
+  async createOrganization(org) {
+    const organization = { ...org };
+    delete organization.connections;
+
+    const created = await this.client.organizations.create(organization);
+
+    if (typeof org.connections !== 'undefined' && org.connections.length > 0) {
+      await Promise.all(org.connections.map(conn => this.client.organizations.addEnabledConnection({ id: created.id }, conn)));
+    }
+
+    return created;
+  }
+
+  async createOrganizations(creates) {
+    await this.client.pool.addEachTask({
+      data: creates || [],
+      generator: item => this.createOrganization(item).then((data) => {
+        this.didCreate(data);
+        this.created += 1;
+      }).catch((err) => {
+        throw new Error(`Problem creating ${this.type} ${this.objString(item)}\n${err}`);
+      })
+    }).promise();
+  }
+
+  async updateOrganization(org, organizations) {
+    const { connections: existingConnections } = await organizations.find(orgToUpdate => orgToUpdate.name === org.name);
+
+    const params = { id: org.id };
+    const { connections } = org;
+
+    delete org.connections;
+    delete org.name;
+    delete org.id;
+
+    await this.client.organizations.update(params, org);
+
+    const connectionsToRemove = existingConnections.filter(c => !connections.find(x => x.connection_id === c.connection_id));
+    const connectionsToAdd = connections.filter(c => !existingConnections.find(x => x.connection_id === c.connection_id));
+    const connectionsToUpdate = connections.filter(c => existingConnections.find(x => x.connection_id === c.connection_id && x.assign_membership_on_login !== c.assign_membership_on_login));
+
+    // Handle updates first
+    await Promise.all(connectionsToUpdate.map(conn => this.client.organizations
+      .updateEnabledConnection(Object.assign({ connection_id: conn.connection_id }, params), { assign_membership_on_login: conn.assign_membership_on_login })
+      .catch(() => {
+        throw new Error(`Problem updating Enabled Connection ${conn.connection_id} for organizations ${params.id}`);
+      })));
+
+    await Promise.all(connectionsToAdd.map(conn => this.client.organizations
+      .addEnabledConnection(params, _.omit(conn, 'connection'))
+      .catch(() => {
+        throw new Error(`Problem adding Enabled Connection ${conn.connection_id} for organizations ${params.id}`);
+      })));
+
+    await Promise.all(connectionsToRemove.map(conn => this.client.organizations
+      .removeEnabledConnection(Object.assign({ connection_id: conn.connection_id }, params))
+      .catch(() => {
+        throw new Error(`Problem removing Enabled Connection ${conn.connection_id} for organizations ${params.id}`);
+      })));
+
+    return params;
+  }
+
+  async updateOrganizations(updates, orgs) {
+    await this.client.pool.addEachTask({
+      data: updates || [],
+      generator: item => this.updateOrganization(item, orgs).then((data) => {
+        this.didUpdate(data);
+        this.updated += 1;
+      }).catch((err) => {
+        throw new Error(`Problem updating ${this.type} ${this.objString(item)}\n${err}`);
+      })
+    }).promise();
+  }
+
+  async getType() {
+    if (this.existing) {
+      return this.existing;
+    }
+
+    if (!this.client.organizations || typeof this.client.organizations.getAll !== 'function') {
+      return [];
+    }
+
+    try {
+      const organizations = await this.client.organizations.getAll({ pagination: true });
+      for (let index = 0; index < organizations.length; index++) {
+        const connections = await this.client.organizations.connections.get({ id: organizations[index].id });
+        organizations[index].connections = connections;
+      }
+      this.existing = organizations;
+      return this.existing;
+    } catch (err) {
+      if (err.statusCode === 404 || err.statusCode === 501) {
+        return [];
+      }
+      throw err;
+    }
+  }
+
+  // Run after connections
+  @order('70')
+  async processChanges(assets) {
+    const { organizations } = assets;
+    // Do nothing if not set
+    if (!organizations) return;
+    // Gets organizations from destination tenant
+    const existing = await this.getType();
+    const changes = calcChanges(organizations, existing, [ 'id', 'name' ]);
+
+    log.debug(`Start processChanges for organizations [delete:${changes.del.length}] [update:${changes.update.length}], [create:${changes.create.length}]`);
+
+    const myChanges = [ { del: changes.del }, { create: changes.create }, { update: changes.update } ];
+
+    await Promise.all(myChanges.map(async (change) => {
+      switch (true) {
+        case change.del && change.del.length > 0:
+          await this.deleteOrganizations(change.del);
+          break;
+        case change.create && change.create.length > 0:
+          await this.createOrganizations(changes.create);
+          break;
+        case change.update && change.update.length > 0:
+          await this.updateOrganizations(change.update, existing);
+          break;
+        default:
+          break;
+      }
+    }));
+  }
+}
diff --git a/tests/auth0/handlers/organizations.tests.js b/tests/auth0/handlers/organizations.tests.js
new file mode 100644
index 0000000..b751d8e
--- /dev/null
+++ b/tests/auth0/handlers/organizations.tests.js
@@ -0,0 +1,365 @@
+const { expect } = require('chai');
+const organizations = require('../../../src/auth0/handlers/organizations');
+
+const pool = {
+  addEachTask: (data) => {
+    if (data.data && data.data.length) {
+      data.generator(data.data[0]);
+    }
+    return { promise: () => null };
+  }
+};
+
+const sampleOrg = {
+  id: '123',
+  name: 'acme',
+  display_name: 'Acme Inc'
+};
+
+const sampleConnection = {
+  connection_id: 'con_123', assign_membership_on_login: true
+};
+const sampleConnection2 = {
+  connection_id: 'con_456', assign_membership_on_login: false
+};
+
+
+describe('#organizations handler', () => {
+  const config = function(key) {
+    return config.data && config.data[key];
+  };
+
+  config.data = {
+    AUTH0_ALLOW_DELETE: true
+  };
+
+  describe('#organizations validate', () => {
+    it('should not allow same id', async () => {
+      const handler = new organizations.default({ client: {}, config });
+      const stageFn = Object.getPrototypeOf(handler).validate;
+      const data = [
+        {
+          id: '123',
+          name: 'Acme'
+        },
+        {
+          id: '123',
+          name: 'Contoso'
+        }
+      ];
+
+      try {
+        await stageFn.apply(handler, [ { organizations: data } ]);
+      } catch (err) {
+        expect(err).to.be.an('object');
+        expect(err.message).to.include('Only one rule must be defined for the same order number in a stage.');
+      }
+    });
+
+    it('should not allow same names', async () => {
+      const handler = new organizations.default({ client: {}, config });
+      const stageFn = Object.getPrototypeOf(handler).validate;
+      const data = [
+        {
+          name: 'Acme'
+        },
+        {
+          name: 'Acme'
+        }
+      ];
+
+      try {
+        await stageFn.apply(handler, [ { organizations: data } ]);
+      } catch (err) {
+        expect(err).to.be.an('object');
+        expect(err.message).to.include('Names must be unique');
+      }
+    });
+
+    it('should pass validation', async () => {
+      const handler = new organizations.default({ client: {}, config });
+      const stageFn = Object.getPrototypeOf(handler).validate;
+      const data = [
+        {
+          name: 'Acme'
+        }
+      ];
+
+      await stageFn.apply(handler, [ { organizations: data } ]);
+    });
+  });
+
+  describe('#organizations process', () => {
+    it('should return empty if no organization asset', async () => {
+      const auth0 = {
+        organizations: {
+        },
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      const stageFn = Object.getPrototypeOf(handler).processChanges;
+      const response = await stageFn.apply(handler, [ { } ]);
+      expect(response).to.equal(undefined);
+    });
+
+    it('should create organization', async () => {
+      const auth0 = {
+        organizations: {
+          create: (data) => {
+            expect(data).to.be.an('object');
+            expect(data.name).to.equal('acme');
+            expect(data.display_name).to.equal('Acme');
+            expect(data.connections).to.equal(undefined);
+            data.id = 'fake';
+            return Promise.resolve(data);
+          },
+          update: () => Promise.resolve([]),
+          delete: () => Promise.resolve([]),
+          getAll: () => Promise.resolve([]),
+          addEnabledConnection: (org, connection) => {
+            expect(org.id).to.equal('fake');
+            expect(connection).to.be.an('object');
+            expect(connection.connection_id).to.equal('123');
+            expect(connection.assign_membership_on_login).to.equal(true);
+            return Promise.resolve(connection);
+          }
+        },
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      const stageFn = Object.getPrototypeOf(handler).processChanges;
+      await stageFn.apply(handler, [
+        {
+          organizations: [
+            {
+              name: 'acme',
+              display_name: 'Acme',
+              connections: [
+                {
+                  connection_id: '123',
+                  assign_membership_on_login: true
+                }
+              ]
+            }
+          ]
+        }
+      ]);
+    });
+
+    it('should get organizations', async () => {
+      const auth0 = {
+        organizations: {
+          getAll: () => Promise.resolve([ sampleOrg ]),
+          connections: {
+            get: () => [
+              sampleConnection
+            ]
+          }
+        },
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      const data = await handler.getType();
+      expect(data).to.deep.equal([ Object.assign({}, sampleOrg, { connections: [ sampleConnection ] }) ]);
+    });
+
+    it('should get all organizations', async () => {
+      const organizationsPage1 = Array.from({ length: 50 }, (v, i) => ({ name: 'acme' + i, display_name: 'Acme ' + i }));
+      const organizationsPage2 = Array.from({ length: 40 }, (v, i) => ({ name: 'acme' + (i + 50), display_name: 'Acme ' + (i + 50) }));
+
+      const auth0 = {
+        organizations: {
+          getAll: () => Promise.resolve([ ...organizationsPage2, ...organizationsPage1 ]),
+          connections: {
+            get: () => Promise.resolve({})
+          }
+        },
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      const data = await handler.getType();
+      expect(data).to.have.length(90);
+    });
+
+    it('should return an empty array for old versions of the sdk', async () => {
+      const auth0 = {
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      const data = await handler.getType();
+      expect(data).to.deep.equal([]);
+    });
+
+    it('should return an empty array for 501 status code', async () => {
+      const auth0 = {
+        organizations: {
+          getAll: () => {
+            const error = new Error('Feature is not yet implemented');
+            error.statusCode = 501;
+            throw error;
+          }
+        },
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      const data = await handler.getType();
+      expect(data).to.deep.equal([]);
+    });
+
+    it('should return an empty array for 404 status code', async () => {
+      const auth0 = {
+        organizations: {
+          getAll: () => {
+            const error = new Error('Not found');
+            error.statusCode = 404;
+            throw error;
+          }
+        },
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      const data = await handler.getType();
+      expect(data).to.deep.equal([]);
+    });
+
+    it('should throw an error for all other failed requests', async () => {
+      const auth0 = {
+        organizations: {
+          getAll: () => {
+            const error = new Error('Bad request');
+            error.statusCode = 500;
+            throw error;
+          }
+        },
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      try {
+        await handler.getType();
+      } catch (error) {
+        expect(error).to.be.an.instanceOf(Error);
+      }
+    });
+
+    it('should call getAll once', async () => {
+      let shouldThrow = false;
+      const auth0 = {
+        organizations: {
+          getAll: () => {
+            if (!shouldThrow) {
+              return [ sampleOrg ];
+            }
+
+            throw new Error('Unexpected');
+          },
+          connections: {
+            get: () => Promise.resolve([])
+          }
+        },
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      let data = await handler.getType();
+      expect(data).to.deep.equal([ sampleOrg ]);
+
+      shouldThrow = true;
+      data = await handler.getType();
+      expect(data).to.deep.equal([ sampleOrg ]);
+    });
+
+    it('should update organizations', async () => {
+      const auth0 = {
+        organizations: {
+          create: () => Promise.resolve([]),
+          update: (params, data) => {
+            expect(params).to.be.an('object');
+            expect(params.id).to.equal('123');
+            expect(data.display_name).to.equal('Acme 2');
+            return Promise.resolve(data);
+          },
+          delete: () => Promise.resolve([]),
+          getAll: () => Promise.resolve([ sampleOrg ]),
+          connections: {
+            get: () => [
+              sampleConnection,
+              sampleConnection2
+            ]
+          },
+          addEnabledConnection: (params, data) => {
+            expect(params).to.be.an('object');
+            expect(params.id).to.equal('123');
+            expect(data).to.be.an('object');
+            expect(data.connection_id).to.equal('con_789');
+            expect(data.assign_membership_on_login).to.equal(false);
+            return Promise.resolve(data);
+          },
+          removeEnabledConnection: (params) => {
+            expect(params).to.be.an('object');
+            expect(params.id).to.equal('123');
+            expect(params.connection_id).to.equal(sampleConnection2.connection_id);
+            return Promise.resolve();
+          },
+          updateEnabledConnection: (params, data) => {
+            expect(params).to.be.an('object');
+            expect(params.id).to.equal('123');
+            expect(params.connection_id).to.equal(sampleConnection.connection_id);
+            expect(data).to.be.an('object');
+            expect(data.assign_membership_on_login).to.equal(false);
+            return Promise.resolve(data);
+          }
+        },
+        pool
+      };
+
+      const handler = new organizations.default({ client: auth0, config });
+      const stageFn = Object.getPrototypeOf(handler).processChanges;
+
+      await stageFn.apply(handler, [
+        {
+          organizations: [
+            {
+              id: '123',
+              name: 'acme',
+              display_name: 'Acme 2',
+              connections: [
+                { connection_id: 'con_123', assign_membership_on_login: false },
+                { connection_id: 'con_789', assign_membership_on_login: false }
+              ]
+            }
+          ]
+        }
+      ]);
+    });
+
+    it('should delete organizations', async () => {
+      const auth0 = {
+        organizations: {
+          create: () => Promise.resolve([]),
+          update: () => Promise.resolve([]),
+          delete: (data) => {
+            expect(data).to.be.an('object');
+            expect(data.id).to.equal(sampleOrg.id);
+            return Promise.resolve(data);
+          },
+          getAll: () => Promise.resolve([ sampleOrg ]),
+          connections: {
+            get: () => []
+          }
+        },
+        pool
+      };
+      const handler = new organizations.default({ client: auth0, config });
+      const stageFn = Object.getPrototypeOf(handler).processChanges;
+      await stageFn.apply(handler, [ { organizations: [ {} ] } ]);
+    });
+  });
+});