diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/extensions/__init__.py
new file mode 100644
index 0000000..181180a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/extensions/__init__.py
@@ -0,0 +1,484 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Extension Node """
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers.databases as databases
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from functools import wraps
+
+# As unicode type is not available in python3
+# If we check a variable is "isinstance(variable, str)
+# it breaks in python 3 as variable type is not string its unicode.
+# We assign basestring as str type if it is python3, unicode
+# if it is python2.
+
+try:
+    unicode = unicode
+except NameError:
+    # 'unicode' is undefined, must be Python 3
+    str = str
+    unicode = str
+    bytes = bytes
+    basestring = (str, bytes)
+else:
+    # 'unicode' exists, must be Python 2
+    str = str
+    unicode = unicode
+    bytes = str
+    basestring = basestring
+
+
+class ExtensionModule(CollectionNodeModule):
+    """
+    class ExtensionModule(Object):
+
+        A collection Node which inherits CollectionNodeModule
+        class and define methods to get child nodes, to load its own
+        javascript file.
+    """
+    NODE_TYPE = "extension"
+    COLLECTION_LABEL = gettext("Extensions")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Initialising the base class
+        """
+        super(ExtensionModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did):
+        """
+        Generate the collection node
+        """
+        yield self.generate_browser_collection_node(did)
+
+    @property
+    def node_inode(self):
+        """
+        If a node have child return True otherwise False
+        """
+        return False
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for extension, when any of the database node is
+        initialized.
+        """
+        return databases.DatabaseModule.NODE_TYPE
+
+
+# Create blueprint of extension module
+blueprint = ExtensionModule(__name__)
+
+
+class ExtensionView(PGChildNodeView):
+    """
+    It is a class for extension node which inherits the
+    properties and methods from NodeView class and define
+    various methods to list, create, update and delete extension.
+
+    Variables:
+    ---------
+    * node_type - tells which type of node it is
+    * parent_ids - id with its type and name of parent nodes
+    * ids - id with type and name of extension module being used.
+    * operations - function routes mappings defined.
+    """
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'eid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{'delete': 'delete'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'avails': [{}, {'get': 'avails'}],
+        'schemas': [{}, {'get': 'schemas'}],
+        'children': [{'get': 'children'}]
+    })
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(
+                    PG_DEFAULT_DRIVER
+                ).connection_manager(kwargs['sid'])
+            self.conn = self.manager.connection(did=kwargs['did'])
+            self.template_path = 'extensions/sql'
+
+            return f(*args, **kwargs)
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did):
+        """
+        It fetches all extensions properties and render into properties
+        tab
+        """
+        SQL = render_template("/".join([self.template_path, 'properties.sql']))
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did):
+        """
+        It lists down the all extensions under the Extensions Collection node
+        """
+        res = []
+        SQL = render_template("/".join([self.template_path, 'properties.sql']))
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['eid'],
+                        did,
+                        row['name'],
+                        'icon-extension'
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    @check_precondition
+    def properties(self, gid, sid, did, eid):
+        """
+        It fetches the properties of a single extension
+        and render in properties tab
+
+        """
+        SQL = render_template("/".join(
+            [self.template_path, 'properties.sql']), eid=eid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        return ajax_response(
+                response=res['rows'][0],
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did):
+        """
+        This function will creates new the extension object
+        """
+        required_args = [
+            'name'
+        ]
+
+        data = request.form if request.form else \
+            json.loads(request.data.decode())
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                    status=410,
+                    success=0,
+                    errormsg=gettext(
+                        "Couldn't find the required parameter (%s)." % arg
+                    )
+                )
+
+        status, res = self.conn.execute_dict(
+            render_template(
+                "/".join([self.template_path, 'create.sql']),
+                data=data
+                )
+            )
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        status, rset = self.conn.execute_dict(
+            render_template(
+                "/".join([self.template_path, 'properties.sql']),
+                ename=data['name']
+            )
+        )
+
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            return jsonify(
+              node=self.blueprint.generate_browser_node(
+                    row['eid'],
+                    did,
+                    row['name'],
+                    'icon-extension'
+                    )
+            )
+
+    @check_precondition
+    def update(self, gid, sid, did, eid):
+        """
+        This function will update extension object
+        """
+        data = request.form if request.form else \
+            json.loads(request.data.decode())
+        SQL = self.getSQL(gid, sid, data, did, eid)
+
+        try:
+            if SQL and isinstance(SQL, basestring) and \
+                    SQL.strip('\n') and SQL.strip(' '):
+                status, res = self.conn.execute_dict(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="Extension updated",
+                    data={
+                        'id': eid,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, eid):
+        """
+        This function will delete drop/drop cascade the extension object
+        """
+        cascade = True if self.cmd == 'delete' else False
+        try:
+            # check if extension with eid exists
+            SQL = render_template("/".join(
+                [self.template_path, 'delete.sql']), eid=eid)
+            status, name = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=name)
+            # drop extension
+            SQL = render_template("/".join(
+                    [self.template_path, 'delete.sql']
+                ), name=name, cascade=cascade)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Extension dropped"),
+                data={
+                    'id': did,
+                    'sid': sid,
+                    'gid': gid,
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, eid=None):
+        """
+        This function to return modified SQL
+        """
+        data = request.args.copy()
+        SQL = self.getSQL(gid, sid, data, did, eid)
+        if SQL and isinstance(SQL, basestring) and SQL.strip('\n') \
+                and SQL.strip(' '):
+            return make_json_response(
+                    data=SQL,
+                    status=200
+                    )
+        else:
+            return make_json_response(
+                    data=gettext('-- Modified SQL --'),
+                    status=200
+                    )
+
+    def getSQL(self, gid, sid, data, did, eid=None):
+        """
+        This function will generate sql from model data
+        """
+        required_args = [
+            'name'
+        ]
+        try:
+            if eid is not None:
+                SQL = render_template("/".join(
+                        [self.template_path, 'properties.sql']
+                    ), eid=eid)
+                status, res = self.conn.execute_dict(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+                old_data = res['rows'][0]
+                for arg in required_args:
+                    if arg not in data:
+                        data[arg] = old_data[arg]
+                SQL = render_template("/".join(
+                            [self.template_path, 'update.sql']
+                        ), data=data, o_data=old_data)
+            else:
+                SQL = render_template("/".join(
+                            [self.template_path, 'create.sql']
+                        ), data=data)
+            return SQL
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def avails(self, gid, sid, did):
+        """
+        This function with fetch all the available extensions
+        """
+        SQL = render_template("/".join([self.template_path, 'extensions.sql']))
+        status, rset = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+        return make_json_response(
+                data=rset['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def schemas(self, gid, sid, did):
+        """
+        This function with fetch all the schemas
+        """
+        SQL = render_template("/".join([self.template_path, 'schemas.sql']))
+        status, rset = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+        return make_json_response(
+                data=rset['rows'],
+                status=200
+                )
+
+    def module_js(self):
+        """
+        This property defines (if javascript) exists for this node.
+        Override this property for your own logic.
+        """
+        return make_response(
+                render_template(
+                    "extensions/js/extensions.js",
+                    _=gettext
+                    ),
+                200, {'Content-Type': 'application/x-javascript'}
+                )
+
+    @check_precondition
+    def sql(self, gid, sid, did, eid):
+        """
+        This function will generate sql for sql panel
+        """
+        SQL = render_template("/".join(
+                [self.template_path, 'properties.sql']
+            ), eid=eid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        result = res['rows'][0]
+
+        SQL = render_template("/".join(
+                [self.template_path, 'create.sql']
+                ),
+            data=result,
+            conn=self.conn,
+            display_comments=True
+        )
+
+        return ajax_response(response=SQL)
+
+    @check_precondition
+    def dependents(self, gid, sid, did, eid):
+        """
+        This function get the dependents and return ajax response
+        for the extension node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            eid: Extension ID
+        """
+        dependents_result = self.get_dependents(self.conn, eid)
+        return ajax_response(
+            response=dependents_result,
+            status=200
+            )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, eid):
+        """
+        This function get the dependencies and return ajax response
+        for the extension node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            lid: Extension ID
+        """
+        dependencies_result = self.get_dependencies(self.conn, eid)
+        return ajax_response(
+            response=dependencies_result,
+            status=200
+            )
+
+# Register and add ExtensionView as blueprint
+ExtensionView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/static/img/coll-extension.png b/web/pgadmin/browser/server_groups/servers/databases/extensions/static/img/coll-extension.png
new file mode 100644
index 0000000000000000000000000000000000000000..eed7ca97a33ef595f448b8621168d531f86d51d5
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/static/img/extension.png b/web/pgadmin/browser/server_groups/servers/databases/extensions/static/img/extension.png
new file mode 100644
index 0000000000000000000000000000000000000000..e3c533347883fc1dec73bcb21b32fc54e3c31732
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/js/extensions.js b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/js/extensions.js
new file mode 100644
index 0000000..170a9a1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/js/extensions.js
@@ -0,0 +1,254 @@
+define(
+      ['jquery', 'underscore', 'underscore.string', 'pgadmin',
+        'pgadmin.browser', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser) {
+
+  /*
+   * Create and Add an Extension Collection into nodes
+   * Params:
+   *   label - Label for Node
+   *   type - Type of Node
+   *   columns - List of columns to show under under properties.
+   */
+  if (!pgBrowser.Nodes['coll-extension']) {
+    var extensions = pgAdmin.Browser.Nodes['coll-extension'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'extension',
+        label: '{{ _('Extension') }}',
+        type: 'coll-extension',
+        columns: ['name', 'owner', 'comment']
+      });
+  };
+
+  /*
+   * Create and Add an Extension Node into nodes
+   * Params:
+   *   parent_type - Name of parent Node
+   *   type - Type of Node
+   *   hasSQL - True if we need to show SQL query Tab control, otherwise False
+   *   canDrop - True to show "Drop Extension" link under Context menu,
+   *    otherwise False
+   *   canDropCascade - True to show "Drop Cascade" link under Context menu,
+   *    otherwise False
+   *   columns - List of columns to show under under properties tab.
+   *   label - Label for Node
+   */
+  if (!pgBrowser.Nodes['extension']) {
+    pgAdmin.Browser.Nodes['extension'] =
+    pgAdmin.Browser.Node.extend({
+      parent_type: 'database',
+      type: 'extension',
+      hasSQL: true,
+      hasDepends: true,
+      canDrop: true,
+      canDropCascade: true,
+      label: '{{ _('Extension') }}',
+
+      Init: function() {
+        if(this.initialized)
+          return;
+
+        this.initialized = true;
+
+        /*
+         * Add "create extension" menu item into context and object menu
+         * for the following nodes:
+         * coll-extension, extension and database.
+         */
+        pgBrowser.add_menus([{
+          name: 'create_extension_on_coll', node: 'coll-extension', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Extension...') }}',
+          icon: 'wcTabIcon icon-extension', data: {action: 'create'}
+        },{
+          name: 'create_extension', node: 'extension', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Extension...') }}',
+          icon: 'wcTabIcon icon-extension', data: {action: 'create'}
+        },{
+          name: 'create_extension', node: 'database', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Extension...') }}',
+          icon: 'wcTabIcon icon-extension', data: {action: 'create'}
+        }
+        ]);
+      },
+
+      /*
+       * Define model for the Node and specify the properties
+       * of the model in schema.
+       */
+      model: pgAdmin.Browser.Node.Model.extend({
+        schema: [
+          {
+            id: 'name', label: '{{ _('Name')}}', first_empty: true,
+            type: 'text', mode: ['properties', 'create', 'edit'],
+            visible: true, url:'avails', disabled: function(m) {
+              return !m.isNew();
+            },
+            transform: function(data) {
+              var res = [];
+              var label = this.model.get('name');
+              if (!this.model.isNew()) {
+                res.push({label: label, value: label});
+              }
+              else {
+                if (data && _.isArray(data)) {
+                  _.each(data, function(d) {
+                    if (d.installed_version === null)
+
+                      /*
+                       * d contains json data and sets into
+                       * select's option control
+                       *
+                       * We need to stringify data because formatter will
+                       * convert Array Object as [Object] string
+                       */
+                      res.push({label: d.name, value: JSON.stringify(d)});
+                  })
+                }
+              }
+              return res;
+            },
+
+            /*
+             * extends NodeAjaxOptionsControl to override the properties
+             * getValueFromDOM which takes stringified data from option of
+             * select control and parse it. And `onChange` takes the stringified
+             * data from select's option, thus convert it to json format and set the
+             * data into Model which is used to enable/disable the schema field.
+             */
+            control: Backform.NodeAjaxOptionsControl.extend({
+              getValueFromDOM: function() {
+                var data = this.formatter.toRaw(
+                  _.unescape(this.$el.find("select").val()), this.model);
+                /*
+                 * return null if data is empty to prevent it from
+                 * throwing parsing error. Adds check as name can be empty
+                 */
+                if (data === '') {
+                  return null;
+                }
+                else if (typeof(data) === 'string') {
+                  data=JSON.parse(data);
+                }
+                return data.name;
+              },
+
+              /*
+               * When name is changed, extract value from its select option and
+               * set attributes values into the model
+               */
+              onChange: function() {
+                Backform.NodeAjaxOptionsControl.prototype.onChange.apply(this, arguments);
+                var selectedValue = this.$el.find("select").val();
+                if (selectedValue.trim() != "") {
+                  var d = this.formatter.toRaw(selectedValue, this.model);
+                  if(typeof(d) === 'string')
+                    d=JSON.parse(d);
+                  var changes = {
+                    'version' : '',
+                    'relocatable': (
+                        (!_.isNull(d.relocatable[0]) && !_.isUndefined(d.relocatable[0])) ?
+                        d.relocatable[0]: ''),
+                    'schema': ((!_.isNull(d.schema[0]) &&
+                          !_.isUndefined(d.schema[0])) ? d.schema[0]: '')
+                    };
+                  this.model.set(changes);
+                }
+                else {
+                  var changes = {'version': '', 'relocatable': true, 'schema': ''};
+                  this.model.set(changes);
+                }
+              },
+            })
+          },
+          {
+            id: 'eid', label: '{{ _('Oid')}}', cell: 'string',
+            type: 'text', disabled: true, mode: ['properties', 'edit', 'create']
+          },
+          {
+            id: 'owner', label:'{{ _('Owner') }}', control: 'node-list-by-name',
+            mode: ['properties'], node: 'role', cell: 'string'
+          },
+          {
+            id: 'schema', label: '{{ _('Schema')}}', type: 'text', control: 'node-ajax-options',
+            mode: ['properties', 'create', 'edit'], group: 'Definition', deps: ['relocatable'],
+            url: 'schemas', first_empty: true, disabled: function(m) {
+
+              /*
+               * enable or disable schema field if model's relocatable
+               * attribute is True or False
+               */
+              return (m.has('relocatable') ? !m.get('relocatable') : false);
+            },
+            transform: function(data) {
+              var res = [];
+              if (data && _.isArray(data)) {
+                _.each(data, function(d) {
+                  res.push({label: d.schema, value: d.schema});
+                })
+              }
+              return res;
+            }
+          },
+          {
+            id: 'relocatable', label: '{{ _('Relocatable?')}}', cell: 'switch',
+            type: 'switch', mode: ['properties'], 'options': {
+              'onText': 'Yes', 'offText': 'No', 'onColor': 'success',
+              'offColor': 'default', 'size': 'small'
+            }
+          },
+          {
+            id: 'version', label: '{{ _('Version')}}', cell: 'string',
+            mode: ['properties', 'create', 'edit'], group: 'Definition',
+            control: 'node-ajax-options', url:'avails', first_empty: true,
+
+            // Transform the data into version for the selected extension.
+            transform: function(data) {
+              res = [];
+              var extension = this.model.get('name');
+              _.each(data, function(dt) {
+                if(dt.name == extension) {
+                  if(dt.version && _.isArray(dt.version)) {
+                    _.each(dt.version, function(v) {
+                      res.push({ label: v, value: v });
+                    });
+                  }
+                }
+              });
+              return res;
+            }
+          },
+          {
+            id: 'comment', label: '{{ _('Comment')}}', cell: 'string',
+            type: 'multiline', disabled: true
+          }
+        ],
+        validate: function() {
+
+          /*
+          * Triggers error messages for name
+          * if it is empty/undefined/null
+          */
+          var err = {},
+            errmsg,
+            name = this.get('name');
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            err['name'] = '{{ _('Name can not be empty!') }}';
+            errmsg = errmsg || err['name'];
+            this.errorModel.set('name', errmsg);
+            return errmsg;
+          }
+          else {
+            this.errorModel.unset('name');
+          }
+          return null;
+        }
+      })
+    })
+  };
+
+  return pgBrowser.Nodes['coll-extension'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/create.sql
new file mode 100644
index 0000000..288a7cc
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/create.sql
@@ -0,0 +1,19 @@
+{#=========================Create new extension======================#}
+{#===Generates comments and code for SQL tab===#}
+{% if display_comments %}
+-- Extension: {{ conn|qtIdent(data.name) }}
+
+-- DROP EXTENSION {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{% if data.name %}
+ CREATE EXTENSION {{ conn|qtIdent(data.name) }}{% if data.schema == '' and data.version == '' %};{% endif %}
+{% if data.schema %}
+
+    SCHEMA {{ conn|qtIdent(data.schema) }}{% if data.version == '' %};{% endif %}
+{% endif %}
+{% if data.version %}
+
+    VERSION {{ conn|qtIdent(data.version) }};
+{% endif %}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/delete.sql
new file mode 100644
index 0000000..44155f6
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/delete.sql
@@ -0,0 +1,8 @@
+{#============================Drop/Cascade Extension by name=========================#}
+{% if eid %}
+SELECT x.extname from pg_extension x
+    WHERE x.oid = {{ eid }}::int
+{% endif %}
+{% if name %}
+DROP EXTENSION {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/extensions.sql b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/extensions.sql
new file mode 100644
index 0000000..bf3979d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/extensions.sql
@@ -0,0 +1,12 @@
+{# ======================Fetch extensions names=====================#}
+SELECT
+    a.name, a.installed_version,
+    array_agg(av.version) as version,
+    array_agg(av.schema) as schema,
+    array_agg(av.superuser) as superuser,
+    array_agg(av.relocatable) as relocatable
+FROM
+    pg_available_extensions a
+    LEFT JOIN pg_available_extension_versions av ON (a.name = av.name)
+GROUP BY a.name, a.installed_version
+ORDER BY a.name
diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/properties.sql
new file mode 100644
index 0000000..f652676
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/properties.sql
@@ -0,0 +1,17 @@
+{#===================Fetch properties of each extension by name or oid===================#}
+SELECT
+    x.oid AS eid, pg_get_userbyid(extowner) AS owner,
+    x.extname AS name, n.nspname AS schema,
+    x.extrelocatable AS relocatable, x.extversion AS version,
+    e.comment
+FROM
+    pg_extension x
+    LEFT JOIN pg_namespace n ON x.extnamespace=n.oid
+    JOIN pg_available_extensions() e(name, default_version, comment) ON x.extname=e.name
+{%- if eid %}
+ WHERE x.oid = {{eid}}::int
+{% elif ename %}
+ WHERE x.extname = {{ename|qtLiteral}}::text
+{% else %}
+ ORDER BY x.extname
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/schemas.sql b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/schemas.sql
new file mode 100644
index 0000000..bd43f09
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/schemas.sql
@@ -0,0 +1,3 @@
+{#===================fetch all schemas==========================#}
+SELECT nspname As schema FROM pg_namespace
+    ORDER BY nspname
diff --git a/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/update.sql
new file mode 100644
index 0000000..c4cd626
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/extensions/templates/extensions/sql/update.sql
@@ -0,0 +1,10 @@
+{# =============Update extension schema============= #}
+{% if data.schema and data.schema != o_data.schema %}
+ALTER EXTENSION {{ conn|qtIdent(o_data.name) }}
+    SET SCHEMA {{ conn|qtIdent(data.schema) }};
+{% endif %}
+{# =============Update extension version============= #}
+{% if data.version and data.version != o_data.version %}
+ALTER EXTENSION {{ conn|qtIdent(o_data.name) }}
+    UPDATE TO {{ conn|qtIdent(data.version) }};
+{% endif %}
